Committed by
Gerrit Code Review
Generalize IntentSynchronizer and separate reactive routing code
* IntentSynchronizer can now handle any intent rather than having use case specific APIs * IntentSynchronizer does not generate or store intents anymore, it only perform synchronization * SdnIpFib generates and manages the procative route-based intents * ReactiveRoutingFib generates and manages the reactive intents * Unit tests have been tightned up to only test single components, rather than multiple components together * PeerConnectivityManager uses meaningful keys when creating intents Change-Id: I4bb036ec8d056f43ece46f7dfc71d5e5a136b77d
Showing
21 changed files
with
1761 additions
and
1497 deletions
1 | +/* | ||
2 | + * Copyright 2015 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.reactive.routing; | ||
18 | + | ||
19 | +/** | ||
20 | + * Specifies the type of an IP address or an IP prefix location. | ||
21 | + */ | ||
22 | +enum LocationType { | ||
23 | + /** | ||
24 | + * The location of an IP address or an IP prefix is in local SDN network. | ||
25 | + */ | ||
26 | + LOCAL, | ||
27 | + /** | ||
28 | + * The location of an IP address or an IP prefix is outside local SDN network. | ||
29 | + */ | ||
30 | + INTERNET, | ||
31 | + /** | ||
32 | + * There is no route for this IP address or IP prefix. | ||
33 | + */ | ||
34 | + NO_ROUTE | ||
35 | +} |
apps/reactive-routing/src/main/java/org/onosproject/reactive/routing/ReactiveRoutingFib.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2015 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.reactive.routing; | ||
18 | + | ||
19 | +import com.google.common.collect.ImmutableList; | ||
20 | +import com.google.common.collect.Maps; | ||
21 | +import org.onlab.packet.Ethernet; | ||
22 | +import org.onlab.packet.IpAddress; | ||
23 | +import org.onlab.packet.IpPrefix; | ||
24 | +import org.onlab.packet.MacAddress; | ||
25 | +import org.onlab.packet.VlanId; | ||
26 | +import org.onosproject.core.ApplicationId; | ||
27 | +import org.onosproject.incubator.net.intf.Interface; | ||
28 | +import org.onosproject.incubator.net.intf.InterfaceService; | ||
29 | +import org.onosproject.net.ConnectPoint; | ||
30 | +import org.onosproject.net.Host; | ||
31 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
32 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
33 | +import org.onosproject.net.flow.TrafficSelector; | ||
34 | +import org.onosproject.net.flow.TrafficTreatment; | ||
35 | +import org.onosproject.net.host.HostService; | ||
36 | +import org.onosproject.net.intent.Constraint; | ||
37 | +import org.onosproject.net.intent.Key; | ||
38 | +import org.onosproject.net.intent.MultiPointToSinglePointIntent; | ||
39 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
40 | +import org.onosproject.routing.IntentRequestListener; | ||
41 | +import org.onosproject.routing.IntentSynchronizationService; | ||
42 | +import org.onosproject.routing.config.RoutingConfigurationService; | ||
43 | +import org.slf4j.Logger; | ||
44 | +import org.slf4j.LoggerFactory; | ||
45 | + | ||
46 | +import java.util.Collections; | ||
47 | +import java.util.HashSet; | ||
48 | +import java.util.Map; | ||
49 | +import java.util.Set; | ||
50 | + | ||
51 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
52 | + | ||
53 | +/** | ||
54 | + * FIB component for reactive routing intents. | ||
55 | + */ | ||
56 | +public class ReactiveRoutingFib implements IntentRequestListener { | ||
57 | + | ||
58 | + private static final int PRIORITY_OFFSET = 100; | ||
59 | + private static final int PRIORITY_MULTIPLIER = 5; | ||
60 | + protected static final ImmutableList<Constraint> CONSTRAINTS | ||
61 | + = ImmutableList.of(new PartialFailureConstraint()); | ||
62 | + | ||
63 | + private final Logger log = LoggerFactory.getLogger(getClass()); | ||
64 | + | ||
65 | + private final ApplicationId appId; | ||
66 | + private final HostService hostService; | ||
67 | + private final RoutingConfigurationService configService; | ||
68 | + private final InterfaceService interfaceService; | ||
69 | + private final IntentSynchronizationService intentSynchronizer; | ||
70 | + | ||
71 | + private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents; | ||
72 | + | ||
73 | + /** | ||
74 | + * Class constructor. | ||
75 | + * | ||
76 | + * @param appId application ID to use to generate intents | ||
77 | + * @param hostService host service | ||
78 | + * @param configService routing configuration service | ||
79 | + * @param interfaceService interface service | ||
80 | + * @param intentSynchronizer intent synchronization service | ||
81 | + */ | ||
82 | + public ReactiveRoutingFib(ApplicationId appId, HostService hostService, | ||
83 | + RoutingConfigurationService configService, | ||
84 | + InterfaceService interfaceService, | ||
85 | + IntentSynchronizationService intentSynchronizer) { | ||
86 | + this.appId = appId; | ||
87 | + this.hostService = hostService; | ||
88 | + this.configService = configService; | ||
89 | + this.interfaceService = interfaceService; | ||
90 | + this.intentSynchronizer = intentSynchronizer; | ||
91 | + | ||
92 | + routeIntents = Maps.newConcurrentMap(); | ||
93 | + } | ||
94 | + | ||
95 | + @Override | ||
96 | + public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) { | ||
97 | + checkNotNull(hostIpAddress); | ||
98 | + Set<ConnectPoint> ingressPoints = | ||
99 | + configService.getBgpPeerConnectPoints(); | ||
100 | + | ||
101 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
102 | + | ||
103 | + if (hostIpAddress.isIp4()) { | ||
104 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
105 | + } else { | ||
106 | + selector.matchEthType(Ethernet.TYPE_IPV6); | ||
107 | + } | ||
108 | + | ||
109 | + // Match the destination IP prefix at the first hop | ||
110 | + IpPrefix ipPrefix = hostIpAddress.toIpPrefix(); | ||
111 | + selector.matchIPDst(ipPrefix); | ||
112 | + | ||
113 | + // Rewrite the destination MAC address | ||
114 | + MacAddress hostMac = null; | ||
115 | + ConnectPoint egressPoint = null; | ||
116 | + for (Host host : hostService.getHostsByIp(hostIpAddress)) { | ||
117 | + if (host.mac() != null) { | ||
118 | + hostMac = host.mac(); | ||
119 | + egressPoint = host.location(); | ||
120 | + break; | ||
121 | + } | ||
122 | + } | ||
123 | + if (hostMac == null) { | ||
124 | + hostService.startMonitoringIp(hostIpAddress); | ||
125 | + return; | ||
126 | + } | ||
127 | + | ||
128 | + TrafficTreatment.Builder treatment = | ||
129 | + DefaultTrafficTreatment.builder().setEthDst(hostMac); | ||
130 | + Key key = Key.of(ipPrefix.toString(), appId); | ||
131 | + int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER | ||
132 | + + PRIORITY_OFFSET; | ||
133 | + MultiPointToSinglePointIntent intent = | ||
134 | + MultiPointToSinglePointIntent.builder() | ||
135 | + .appId(appId) | ||
136 | + .key(key) | ||
137 | + .selector(selector.build()) | ||
138 | + .treatment(treatment.build()) | ||
139 | + .ingressPoints(ingressPoints) | ||
140 | + .egressPoint(egressPoint) | ||
141 | + .priority(priority) | ||
142 | + .constraints(CONSTRAINTS) | ||
143 | + .build(); | ||
144 | + | ||
145 | + log.trace("Generates ConnectivityInternetToHost intent {}", intent); | ||
146 | + submitReactiveIntent(ipPrefix, intent); | ||
147 | + } | ||
148 | + | ||
149 | + @Override | ||
150 | + public void setUpConnectivityHostToInternet(IpAddress hostIp, IpPrefix prefix, | ||
151 | + IpAddress nextHopIpAddress) { | ||
152 | + // Find the attachment point (egress interface) of the next hop | ||
153 | + Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress); | ||
154 | + if (egressInterface == null) { | ||
155 | + log.warn("No outgoing interface found for {}", | ||
156 | + nextHopIpAddress); | ||
157 | + return; | ||
158 | + } | ||
159 | + | ||
160 | + Set<Host> hosts = hostService.getHostsByIp(nextHopIpAddress); | ||
161 | + if (hosts.isEmpty()) { | ||
162 | + log.warn("No host found for next hop IP address"); | ||
163 | + return; | ||
164 | + } | ||
165 | + MacAddress nextHopMacAddress = null; | ||
166 | + for (Host host : hosts) { | ||
167 | + nextHopMacAddress = host.mac(); | ||
168 | + break; | ||
169 | + } | ||
170 | + | ||
171 | + hosts = hostService.getHostsByIp(hostIp); | ||
172 | + if (hosts.isEmpty()) { | ||
173 | + log.warn("No host found for host IP address"); | ||
174 | + return; | ||
175 | + } | ||
176 | + Host host = hosts.stream().findFirst().get(); | ||
177 | + ConnectPoint ingressPoint = host.location(); | ||
178 | + | ||
179 | + // Generate the intent itself | ||
180 | + ConnectPoint egressPort = egressInterface.connectPoint(); | ||
181 | + log.debug("Generating intent for prefix {}, next hop mac {}", | ||
182 | + prefix, nextHopMacAddress); | ||
183 | + | ||
184 | + // Match the destination IP prefix at the first hop | ||
185 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
186 | + if (prefix.isIp4()) { | ||
187 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
188 | + selector.matchIPDst(prefix); | ||
189 | + } else { | ||
190 | + selector.matchEthType(Ethernet.TYPE_IPV6); | ||
191 | + selector.matchIPv6Dst(prefix); | ||
192 | + } | ||
193 | + | ||
194 | + // Rewrite the destination MAC address | ||
195 | + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() | ||
196 | + .setEthDst(nextHopMacAddress); | ||
197 | + if (!egressInterface.vlan().equals(VlanId.NONE)) { | ||
198 | + treatment.setVlanId(egressInterface.vlan()); | ||
199 | + // If we set VLAN ID, we have to make sure a VLAN tag exists. | ||
200 | + // TODO support no VLAN -> VLAN routing | ||
201 | + selector.matchVlanId(VlanId.ANY); | ||
202 | + } | ||
203 | + | ||
204 | + int priority = prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; | ||
205 | + Key key = Key.of(prefix.toString() + "-reactive", appId); | ||
206 | + MultiPointToSinglePointIntent intent = MultiPointToSinglePointIntent.builder() | ||
207 | + .appId(appId) | ||
208 | + .key(key) | ||
209 | + .selector(selector.build()) | ||
210 | + .treatment(treatment.build()) | ||
211 | + .ingressPoints(Collections.singleton(ingressPoint)) | ||
212 | + .egressPoint(egressPort) | ||
213 | + .priority(priority) | ||
214 | + .constraints(CONSTRAINTS) | ||
215 | + .build(); | ||
216 | + | ||
217 | + submitReactiveIntent(prefix, intent); | ||
218 | + } | ||
219 | + | ||
220 | + @Override | ||
221 | + public void setUpConnectivityHostToHost(IpAddress dstIpAddress, | ||
222 | + IpAddress srcIpAddress, | ||
223 | + MacAddress srcMacAddress, | ||
224 | + ConnectPoint srcConnectPoint) { | ||
225 | + checkNotNull(dstIpAddress); | ||
226 | + checkNotNull(srcIpAddress); | ||
227 | + checkNotNull(srcMacAddress); | ||
228 | + checkNotNull(srcConnectPoint); | ||
229 | + | ||
230 | + IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix(); | ||
231 | + IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix(); | ||
232 | + ConnectPoint dstConnectPoint = null; | ||
233 | + MacAddress dstMacAddress = null; | ||
234 | + | ||
235 | + for (Host host : hostService.getHostsByIp(dstIpAddress)) { | ||
236 | + if (host.mac() != null) { | ||
237 | + dstMacAddress = host.mac(); | ||
238 | + dstConnectPoint = host.location(); | ||
239 | + break; | ||
240 | + } | ||
241 | + } | ||
242 | + if (dstMacAddress == null) { | ||
243 | + hostService.startMonitoringIp(dstIpAddress); | ||
244 | + return; | ||
245 | + } | ||
246 | + | ||
247 | + // | ||
248 | + // Handle intent from source host to destination host | ||
249 | + // | ||
250 | + MultiPointToSinglePointIntent srcToDstIntent = | ||
251 | + hostToHostIntentGenerator(dstIpAddress, dstConnectPoint, | ||
252 | + dstMacAddress, srcConnectPoint); | ||
253 | + submitReactiveIntent(dstIpPrefix, srcToDstIntent); | ||
254 | + | ||
255 | + // | ||
256 | + // Handle intent from destination host to source host | ||
257 | + // | ||
258 | + | ||
259 | + // Since we proactively handle the intent from destination host to | ||
260 | + // source host, we should check whether there is an exiting intent | ||
261 | + // first. | ||
262 | + if (mp2pIntentExists(srcIpPrefix)) { | ||
263 | + updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint); | ||
264 | + return; | ||
265 | + } else { | ||
266 | + // There is no existing intent, create a new one. | ||
267 | + MultiPointToSinglePointIntent dstToSrcIntent = | ||
268 | + hostToHostIntentGenerator(srcIpAddress, srcConnectPoint, | ||
269 | + srcMacAddress, dstConnectPoint); | ||
270 | + submitReactiveIntent(srcIpPrefix, dstToSrcIntent); | ||
271 | + } | ||
272 | + } | ||
273 | + | ||
274 | + /** | ||
275 | + * Generates MultiPointToSinglePointIntent for both source host and | ||
276 | + * destination host located in local SDN network. | ||
277 | + * | ||
278 | + * @param dstIpAddress the destination IP address | ||
279 | + * @param dstConnectPoint the destination host connect point | ||
280 | + * @param dstMacAddress the MAC address of destination host | ||
281 | + * @param srcConnectPoint the connect point where packet-in from | ||
282 | + * @return the generated MultiPointToSinglePointIntent | ||
283 | + */ | ||
284 | + private MultiPointToSinglePointIntent hostToHostIntentGenerator( | ||
285 | + IpAddress dstIpAddress, | ||
286 | + ConnectPoint dstConnectPoint, | ||
287 | + MacAddress dstMacAddress, | ||
288 | + ConnectPoint srcConnectPoint) { | ||
289 | + checkNotNull(dstIpAddress); | ||
290 | + checkNotNull(dstConnectPoint); | ||
291 | + checkNotNull(dstMacAddress); | ||
292 | + checkNotNull(srcConnectPoint); | ||
293 | + | ||
294 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
295 | + ingressPoints.add(srcConnectPoint); | ||
296 | + IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix(); | ||
297 | + | ||
298 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
299 | + if (dstIpAddress.isIp4()) { | ||
300 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
301 | + selector.matchIPDst(dstIpPrefix); | ||
302 | + } else { | ||
303 | + selector.matchEthType(Ethernet.TYPE_IPV6); | ||
304 | + selector.matchIPv6Dst(dstIpPrefix); | ||
305 | + } | ||
306 | + | ||
307 | + // Rewrite the destination MAC address | ||
308 | + TrafficTreatment.Builder treatment = | ||
309 | + DefaultTrafficTreatment.builder().setEthDst(dstMacAddress); | ||
310 | + | ||
311 | + Key key = Key.of(dstIpPrefix.toString(), appId); | ||
312 | + int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER | ||
313 | + + PRIORITY_OFFSET; | ||
314 | + MultiPointToSinglePointIntent intent = | ||
315 | + MultiPointToSinglePointIntent.builder() | ||
316 | + .appId(appId) | ||
317 | + .key(key) | ||
318 | + .selector(selector.build()) | ||
319 | + .treatment(treatment.build()) | ||
320 | + .ingressPoints(ingressPoints) | ||
321 | + .egressPoint(dstConnectPoint) | ||
322 | + .priority(priority) | ||
323 | + .constraints(CONSTRAINTS) | ||
324 | + .build(); | ||
325 | + | ||
326 | + log.trace("Generates ConnectivityHostToHost = {} ", intent); | ||
327 | + return intent; | ||
328 | + } | ||
329 | + | ||
330 | + @Override | ||
331 | + public void updateExistingMp2pIntent(IpPrefix ipPrefix, | ||
332 | + ConnectPoint ingressConnectPoint) { | ||
333 | + checkNotNull(ipPrefix); | ||
334 | + checkNotNull(ingressConnectPoint); | ||
335 | + | ||
336 | + MultiPointToSinglePointIntent existingIntent = | ||
337 | + getExistingMp2pIntent(ipPrefix); | ||
338 | + if (existingIntent != null) { | ||
339 | + Set<ConnectPoint> ingressPoints = existingIntent.ingressPoints(); | ||
340 | + // Add host connect point into ingressPoints of the existing intent | ||
341 | + if (ingressPoints.add(ingressConnectPoint)) { | ||
342 | + MultiPointToSinglePointIntent updatedMp2pIntent = | ||
343 | + MultiPointToSinglePointIntent.builder() | ||
344 | + .appId(appId) | ||
345 | + .key(existingIntent.key()) | ||
346 | + .selector(existingIntent.selector()) | ||
347 | + .treatment(existingIntent.treatment()) | ||
348 | + .ingressPoints(ingressPoints) | ||
349 | + .egressPoint(existingIntent.egressPoint()) | ||
350 | + .priority(existingIntent.priority()) | ||
351 | + .constraints(CONSTRAINTS) | ||
352 | + .build(); | ||
353 | + | ||
354 | + log.trace("Update an existing MultiPointToSinglePointIntent " | ||
355 | + + "to new intent = {} ", updatedMp2pIntent); | ||
356 | + submitReactiveIntent(ipPrefix, updatedMp2pIntent); | ||
357 | + } | ||
358 | + // If adding ingressConnectPoint to ingressPoints failed, it | ||
359 | + // because between the time interval from checking existing intent | ||
360 | + // to generating new intent, onos updated this intent due to other | ||
361 | + // packet-in and the new intent also includes the | ||
362 | + // ingressConnectPoint. This will not affect reactive routing. | ||
363 | + } | ||
364 | + } | ||
365 | + | ||
366 | + /** | ||
367 | + * Submits a reactive intent to the intent synchronizer. | ||
368 | + * | ||
369 | + * @param ipPrefix IP prefix of the intent | ||
370 | + * @param intent intent to submit | ||
371 | + */ | ||
372 | + void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) { | ||
373 | + routeIntents.put(ipPrefix, intent); | ||
374 | + | ||
375 | + intentSynchronizer.submit(intent); | ||
376 | + } | ||
377 | + | ||
378 | + /** | ||
379 | + * Gets the existing MultiPointToSinglePointIntent from memory for a given | ||
380 | + * IP prefix. | ||
381 | + * | ||
382 | + * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent | ||
383 | + * @return the MultiPointToSinglePointIntent if found, otherwise null | ||
384 | + */ | ||
385 | + private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix ipPrefix) { | ||
386 | + checkNotNull(ipPrefix); | ||
387 | + return routeIntents.get(ipPrefix); | ||
388 | + } | ||
389 | + | ||
390 | + @Override | ||
391 | + public boolean mp2pIntentExists(IpPrefix ipPrefix) { | ||
392 | + checkNotNull(ipPrefix); | ||
393 | + return routeIntents.get(ipPrefix) != null; | ||
394 | + } | ||
395 | +} |
... | @@ -25,27 +25,39 @@ import org.onlab.packet.EthType; | ... | @@ -25,27 +25,39 @@ import org.onlab.packet.EthType; |
25 | import org.onlab.packet.Ethernet; | 25 | import org.onlab.packet.Ethernet; |
26 | import org.onlab.packet.IPv4; | 26 | import org.onlab.packet.IPv4; |
27 | import org.onlab.packet.Ip4Address; | 27 | import org.onlab.packet.Ip4Address; |
28 | +import org.onlab.packet.Ip6Address; | ||
28 | import org.onlab.packet.IpAddress; | 29 | import org.onlab.packet.IpAddress; |
30 | +import org.onlab.packet.IpPrefix; | ||
29 | import org.onlab.packet.MacAddress; | 31 | import org.onlab.packet.MacAddress; |
30 | import org.onosproject.core.ApplicationId; | 32 | import org.onosproject.core.ApplicationId; |
31 | import org.onosproject.core.CoreService; | 33 | import org.onosproject.core.CoreService; |
34 | +import org.onosproject.incubator.net.intf.Interface; | ||
35 | +import org.onosproject.incubator.net.intf.InterfaceService; | ||
32 | import org.onosproject.net.ConnectPoint; | 36 | import org.onosproject.net.ConnectPoint; |
37 | +import org.onosproject.net.Host; | ||
33 | import org.onosproject.net.flow.DefaultTrafficSelector; | 38 | import org.onosproject.net.flow.DefaultTrafficSelector; |
34 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 39 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
35 | import org.onosproject.net.flow.TrafficSelector; | 40 | import org.onosproject.net.flow.TrafficSelector; |
36 | import org.onosproject.net.flow.TrafficTreatment; | 41 | import org.onosproject.net.flow.TrafficTreatment; |
42 | +import org.onosproject.net.host.HostService; | ||
37 | import org.onosproject.net.packet.DefaultOutboundPacket; | 43 | import org.onosproject.net.packet.DefaultOutboundPacket; |
38 | import org.onosproject.net.packet.InboundPacket; | 44 | import org.onosproject.net.packet.InboundPacket; |
39 | import org.onosproject.net.packet.OutboundPacket; | 45 | import org.onosproject.net.packet.OutboundPacket; |
40 | import org.onosproject.net.packet.PacketContext; | 46 | import org.onosproject.net.packet.PacketContext; |
41 | import org.onosproject.net.packet.PacketProcessor; | 47 | import org.onosproject.net.packet.PacketProcessor; |
42 | import org.onosproject.net.packet.PacketService; | 48 | import org.onosproject.net.packet.PacketService; |
49 | +import org.onosproject.routing.IntentRequestListener; | ||
50 | +import org.onosproject.routing.RouteEntry; | ||
43 | import org.onosproject.routing.RoutingService; | 51 | import org.onosproject.routing.RoutingService; |
52 | +import org.onosproject.routing.SdnIpService; | ||
44 | import org.onosproject.routing.config.RoutingConfigurationService; | 53 | import org.onosproject.routing.config.RoutingConfigurationService; |
45 | import org.slf4j.Logger; | 54 | import org.slf4j.Logger; |
46 | 55 | ||
47 | import java.nio.ByteBuffer; | 56 | import java.nio.ByteBuffer; |
57 | +import java.util.Optional; | ||
58 | +import java.util.Set; | ||
48 | 59 | ||
60 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
49 | import static org.onlab.packet.Ethernet.TYPE_ARP; | 61 | import static org.onlab.packet.Ethernet.TYPE_ARP; |
50 | import static org.onlab.packet.Ethernet.TYPE_IPV4; | 62 | import static org.onlab.packet.Ethernet.TYPE_IPV4; |
51 | import static org.onosproject.net.packet.PacketPriority.REACTIVE; | 63 | import static org.onosproject.net.packet.PacketPriority.REACTIVE; |
... | @@ -74,16 +86,32 @@ public class SdnIpReactiveRouting { | ... | @@ -74,16 +86,32 @@ public class SdnIpReactiveRouting { |
74 | protected RoutingService routingService; | 86 | protected RoutingService routingService; |
75 | 87 | ||
76 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 88 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
89 | + protected SdnIpService sdnIpService; | ||
90 | + | ||
91 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
77 | protected RoutingConfigurationService config; | 92 | protected RoutingConfigurationService config; |
78 | 93 | ||
94 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
95 | + protected InterfaceService interfaceService; | ||
96 | + | ||
97 | + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | ||
98 | + protected HostService hostService; | ||
99 | + | ||
79 | private ApplicationId appId; | 100 | private ApplicationId appId; |
80 | 101 | ||
102 | + private IntentRequestListener intentRequestListener; | ||
103 | + | ||
81 | private ReactiveRoutingProcessor processor = | 104 | private ReactiveRoutingProcessor processor = |
82 | new ReactiveRoutingProcessor(); | 105 | new ReactiveRoutingProcessor(); |
83 | 106 | ||
84 | @Activate | 107 | @Activate |
85 | public void activate() { | 108 | public void activate() { |
86 | appId = coreService.registerApplication(APP_NAME); | 109 | appId = coreService.registerApplication(APP_NAME); |
110 | + | ||
111 | + intentRequestListener = new ReactiveRoutingFib(appId, hostService, | ||
112 | + config, interfaceService, | ||
113 | + sdnIpService.getIntentSynchronizationService()); | ||
114 | + | ||
87 | packetService.addProcessor(processor, PacketProcessor.director(2)); | 115 | packetService.addProcessor(processor, PacketProcessor.director(2)); |
88 | requestIntercepts(); | 116 | requestIntercepts(); |
89 | log.info("SDN-IP Reactive Routing Started"); | 117 | log.info("SDN-IP Reactive Routing Started"); |
... | @@ -168,12 +196,11 @@ public class SdnIpReactiveRouting { | ... | @@ -168,12 +196,11 @@ public class SdnIpReactiveRouting { |
168 | IpAddress srcIp = | 196 | IpAddress srcIp = |
169 | IpAddress.valueOf(ipv4Packet.getSourceAddress()); | 197 | IpAddress.valueOf(ipv4Packet.getSourceAddress()); |
170 | MacAddress srcMac = ethPkt.getSourceMAC(); | 198 | MacAddress srcMac = ethPkt.getSourceMAC(); |
171 | - routingService.packetReactiveProcessor(dstIp, srcIp, | 199 | + packetReactiveProcessor(dstIp, srcIp, srcConnectPoint, srcMac); |
172 | - srcConnectPoint, srcMac); | ||
173 | 200 | ||
174 | // TODO emit packet first or packetReactiveProcessor first | 201 | // TODO emit packet first or packetReactiveProcessor first |
175 | ConnectPoint egressConnectPoint = null; | 202 | ConnectPoint egressConnectPoint = null; |
176 | - egressConnectPoint = routingService.getEgressConnectPoint(dstIp); | 203 | + egressConnectPoint = getEgressConnectPoint(dstIp); |
177 | if (egressConnectPoint != null) { | 204 | if (egressConnectPoint != null) { |
178 | forwardPacketToDst(context, egressConnectPoint); | 205 | forwardPacketToDst(context, egressConnectPoint); |
179 | } | 206 | } |
... | @@ -185,6 +212,170 @@ public class SdnIpReactiveRouting { | ... | @@ -185,6 +212,170 @@ public class SdnIpReactiveRouting { |
185 | } | 212 | } |
186 | 213 | ||
187 | /** | 214 | /** |
215 | + * Routes packet reactively. | ||
216 | + * | ||
217 | + * @param dstIpAddress the destination IP address of a packet | ||
218 | + * @param srcIpAddress the source IP address of a packet | ||
219 | + * @param srcConnectPoint the connect point where a packet comes from | ||
220 | + * @param srcMacAddress the source MAC address of a packet | ||
221 | + */ | ||
222 | + private void packetReactiveProcessor(IpAddress dstIpAddress, | ||
223 | + IpAddress srcIpAddress, | ||
224 | + ConnectPoint srcConnectPoint, | ||
225 | + MacAddress srcMacAddress) { | ||
226 | + checkNotNull(dstIpAddress); | ||
227 | + checkNotNull(srcIpAddress); | ||
228 | + checkNotNull(srcConnectPoint); | ||
229 | + checkNotNull(srcMacAddress); | ||
230 | + | ||
231 | + // | ||
232 | + // Step1: Try to update the existing intent first if it exists. | ||
233 | + // | ||
234 | + IpPrefix ipPrefix = null; | ||
235 | + RouteEntry routeEntry = null; | ||
236 | + if (config.isIpAddressLocal(dstIpAddress)) { | ||
237 | + if (dstIpAddress.isIp4()) { | ||
238 | + ipPrefix = IpPrefix.valueOf(dstIpAddress, | ||
239 | + Ip4Address.BIT_LENGTH); | ||
240 | + } else { | ||
241 | + ipPrefix = IpPrefix.valueOf(dstIpAddress, | ||
242 | + Ip6Address.BIT_LENGTH); | ||
243 | + } | ||
244 | + } else { | ||
245 | + // Get IP prefix from BGP route table | ||
246 | + routeEntry = routingService.getLongestMatchableRouteEntry(dstIpAddress); | ||
247 | + if (routeEntry != null) { | ||
248 | + ipPrefix = routeEntry.prefix(); | ||
249 | + } | ||
250 | + } | ||
251 | + if (ipPrefix != null | ||
252 | + && intentRequestListener.mp2pIntentExists(ipPrefix)) { | ||
253 | + intentRequestListener.updateExistingMp2pIntent(ipPrefix, | ||
254 | + srcConnectPoint); | ||
255 | + return; | ||
256 | + } | ||
257 | + | ||
258 | + // | ||
259 | + // Step2: There is no existing intent for the destination IP address. | ||
260 | + // Check whether it is necessary to create a new one. If necessary then | ||
261 | + // create a new one. | ||
262 | + // | ||
263 | + TrafficType trafficType = | ||
264 | + trafficTypeClassifier(srcConnectPoint, dstIpAddress); | ||
265 | + | ||
266 | + switch (trafficType) { | ||
267 | + case HOST_TO_INTERNET: | ||
268 | + // If the destination IP address is outside the local SDN network. | ||
269 | + // The Step 1 has already handled it. We do not need to do anything here. | ||
270 | + intentRequestListener.setUpConnectivityHostToInternet(srcIpAddress, | ||
271 | + ipPrefix, routeEntry.nextHop()); | ||
272 | + break; | ||
273 | + case INTERNET_TO_HOST: | ||
274 | + intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress); | ||
275 | + break; | ||
276 | + case HOST_TO_HOST: | ||
277 | + intentRequestListener.setUpConnectivityHostToHost(dstIpAddress, | ||
278 | + srcIpAddress, srcMacAddress, srcConnectPoint); | ||
279 | + break; | ||
280 | + case INTERNET_TO_INTERNET: | ||
281 | + log.trace("This is transit traffic, " | ||
282 | + + "the intent should be preinstalled already"); | ||
283 | + break; | ||
284 | + case DROP: | ||
285 | + // TODO here should setUpDropPacketIntent(...); | ||
286 | + // We need a new type of intent here. | ||
287 | + break; | ||
288 | + case UNKNOWN: | ||
289 | + log.trace("This is unknown traffic, so we do nothing"); | ||
290 | + break; | ||
291 | + default: | ||
292 | + break; | ||
293 | + } | ||
294 | + } | ||
295 | + | ||
296 | + /** | ||
297 | + * Classifies the traffic and return the traffic type. | ||
298 | + * | ||
299 | + * @param srcConnectPoint the connect point where the packet comes from | ||
300 | + * @param dstIp the destination IP address in packet | ||
301 | + * @return the traffic type which this packet belongs to | ||
302 | + */ | ||
303 | + private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint, | ||
304 | + IpAddress dstIp) { | ||
305 | + LocationType dstIpLocationType = getLocationType(dstIp); | ||
306 | + Optional<Interface> srcInterface = | ||
307 | + interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst(); | ||
308 | + | ||
309 | + switch (dstIpLocationType) { | ||
310 | + case INTERNET: | ||
311 | + if (!srcInterface.isPresent()) { | ||
312 | + return TrafficType.HOST_TO_INTERNET; | ||
313 | + } else { | ||
314 | + return TrafficType.INTERNET_TO_INTERNET; | ||
315 | + } | ||
316 | + case LOCAL: | ||
317 | + if (!srcInterface.isPresent()) { | ||
318 | + return TrafficType.HOST_TO_HOST; | ||
319 | + } else { | ||
320 | + // TODO Currently we only consider local public prefixes. | ||
321 | + // In the future, we will consider the local private prefixes. | ||
322 | + // If dstIpLocationType is a local private, we should return | ||
323 | + // TrafficType.DROP. | ||
324 | + return TrafficType.INTERNET_TO_HOST; | ||
325 | + } | ||
326 | + case NO_ROUTE: | ||
327 | + return TrafficType.DROP; | ||
328 | + default: | ||
329 | + return TrafficType.UNKNOWN; | ||
330 | + } | ||
331 | + } | ||
332 | + | ||
333 | + /** | ||
334 | + * Evaluates the location of an IP address and returns the location type. | ||
335 | + * | ||
336 | + * @param ipAddress the IP address to evaluate | ||
337 | + * @return the IP address location type | ||
338 | + */ | ||
339 | + private LocationType getLocationType(IpAddress ipAddress) { | ||
340 | + if (config.isIpAddressLocal(ipAddress)) { | ||
341 | + return LocationType.LOCAL; | ||
342 | + } else if (routingService.getLongestMatchableRouteEntry(ipAddress) != null) { | ||
343 | + return LocationType.INTERNET; | ||
344 | + } else { | ||
345 | + return LocationType.NO_ROUTE; | ||
346 | + } | ||
347 | + } | ||
348 | + | ||
349 | + public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) { | ||
350 | + LocationType type = getLocationType(dstIpAddress); | ||
351 | + if (type == LocationType.LOCAL) { | ||
352 | + Set<Host> hosts = hostService.getHostsByIp(dstIpAddress); | ||
353 | + if (!hosts.isEmpty()) { | ||
354 | + return hosts.iterator().next().location(); | ||
355 | + } else { | ||
356 | + hostService.startMonitoringIp(dstIpAddress); | ||
357 | + return null; | ||
358 | + } | ||
359 | + } else if (type == LocationType.INTERNET) { | ||
360 | + IpAddress nextHopIpAddress = null; | ||
361 | + RouteEntry routeEntry = routingService.getLongestMatchableRouteEntry(dstIpAddress); | ||
362 | + if (routeEntry != null) { | ||
363 | + nextHopIpAddress = routeEntry.nextHop(); | ||
364 | + Interface it = interfaceService.getMatchingInterface(nextHopIpAddress); | ||
365 | + if (it != null) { | ||
366 | + return it.connectPoint(); | ||
367 | + } else { | ||
368 | + return null; | ||
369 | + } | ||
370 | + } else { | ||
371 | + return null; | ||
372 | + } | ||
373 | + } else { | ||
374 | + return null; | ||
375 | + } | ||
376 | + } | ||
377 | + | ||
378 | + /** | ||
188 | * Emits the specified packet onto the network. | 379 | * Emits the specified packet onto the network. |
189 | * | 380 | * |
190 | * @param context the packet context | 381 | * @param context the packet context | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.reactive.routing; | ||
18 | + | ||
19 | +/** | ||
20 | + * Specifies the type of traffic. | ||
21 | + * <p> | ||
22 | + * We classify traffic by the first packet of each traffic. | ||
23 | + * </p> | ||
24 | + */ | ||
25 | +enum TrafficType { | ||
26 | + /** | ||
27 | + * Traffic from a host located in local SDN network wants to | ||
28 | + * communicate with destination host located in Internet (outside | ||
29 | + * local SDN network). | ||
30 | + */ | ||
31 | + HOST_TO_INTERNET, | ||
32 | + /** | ||
33 | + * Traffic from Internet wants to communicate with a host located | ||
34 | + * in local SDN network. | ||
35 | + */ | ||
36 | + INTERNET_TO_HOST, | ||
37 | + /** | ||
38 | + * Both the source host and destination host of a traffic are in | ||
39 | + * local SDN network. | ||
40 | + */ | ||
41 | + HOST_TO_HOST, | ||
42 | + /** | ||
43 | + * Traffic from Internet wants to traverse local SDN network. | ||
44 | + */ | ||
45 | + INTERNET_TO_INTERNET, | ||
46 | + /** | ||
47 | + * Any traffic wants to communicate with a destination which has | ||
48 | + * no route, or traffic from Internet wants to access a local private | ||
49 | + * IP address. | ||
50 | + */ | ||
51 | + DROP, | ||
52 | + /** | ||
53 | + * Traffic does not belong to the types above. | ||
54 | + */ | ||
55 | + UNKNOWN | ||
56 | +} |
... | @@ -47,6 +47,16 @@ public interface IntentRequestListener { | ... | @@ -47,6 +47,16 @@ public interface IntentRequestListener { |
47 | ConnectPoint srcConnectPoint); | 47 | ConnectPoint srcConnectPoint); |
48 | 48 | ||
49 | /** | 49 | /** |
50 | + * Sets up connectivity for packet from a local host to the Internet. | ||
51 | + * | ||
52 | + * @param hostIp IP address of the local host | ||
53 | + * @param prefix external IP prefix that the host is talking to | ||
54 | + * @param nextHopIpAddress IP address of the next hop router for the prefix | ||
55 | + */ | ||
56 | + void setUpConnectivityHostToInternet(IpAddress hostIp, IpPrefix prefix, | ||
57 | + IpAddress nextHopIpAddress); | ||
58 | + | ||
59 | + /** | ||
50 | * Adds one new ingress connect point into ingress points of an existing | 60 | * Adds one new ingress connect point into ingress points of an existing |
51 | * intent and resubmits the new intent. | 61 | * intent and resubmits the new intent. |
52 | * <p> | 62 | * <p> | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.routing; | ||
18 | + | ||
19 | +import org.onosproject.net.intent.Intent; | ||
20 | + | ||
21 | +/** | ||
22 | + * Submits and withdraws intents to the IntentService from a single point in | ||
23 | + * the cluster at any one time. The provided intents will be synchronized with | ||
24 | + * the IntentService on leadership change. | ||
25 | + */ | ||
26 | +public interface IntentSynchronizationService { | ||
27 | + | ||
28 | + /** | ||
29 | + * Submits and intent to the synchronizer. | ||
30 | + * <p> | ||
31 | + * The intent will be submitted directly to the IntentService if this node | ||
32 | + * is the leader, otherwise it will be stored in the synchronizer for | ||
33 | + * synchronization if this node becomes the leader. | ||
34 | + * </p> | ||
35 | + * | ||
36 | + * @param intent intent to submit | ||
37 | + */ | ||
38 | + void submit(Intent intent); | ||
39 | + | ||
40 | + /** | ||
41 | + * Withdraws an intent from the synchronizer. | ||
42 | + * <p> | ||
43 | + * The intent will be withdrawn directly from the IntentService if this node | ||
44 | + * is the leader. The intent will be removed from the synchronizer's | ||
45 | + * in-memory storage. | ||
46 | + * </p> | ||
47 | + * | ||
48 | + * @param intent intent to withdraw | ||
49 | + */ | ||
50 | + void withdraw(Intent intent); | ||
51 | +} |
... | @@ -16,8 +16,6 @@ | ... | @@ -16,8 +16,6 @@ |
16 | package org.onosproject.routing; | 16 | package org.onosproject.routing; |
17 | 17 | ||
18 | import org.onlab.packet.IpAddress; | 18 | import org.onlab.packet.IpAddress; |
19 | -import org.onlab.packet.MacAddress; | ||
20 | -import org.onosproject.net.ConnectPoint; | ||
21 | import org.onosproject.routing.config.BgpConfig; | 19 | import org.onosproject.routing.config.BgpConfig; |
22 | 20 | ||
23 | import java.util.Collection; | 21 | import java.util.Collection; |
... | @@ -32,63 +30,6 @@ public interface RoutingService { | ... | @@ -32,63 +30,6 @@ public interface RoutingService { |
32 | Class<BgpConfig> CONFIG_CLASS = BgpConfig.class; | 30 | Class<BgpConfig> CONFIG_CLASS = BgpConfig.class; |
33 | 31 | ||
34 | /** | 32 | /** |
35 | - * Specifies the type of an IP address or an IP prefix location. | ||
36 | - */ | ||
37 | - enum LocationType { | ||
38 | - /** | ||
39 | - * The location of an IP address or an IP prefix is in local SDN network. | ||
40 | - */ | ||
41 | - LOCAL, | ||
42 | - /** | ||
43 | - * The location of an IP address or an IP prefix is outside local SDN network. | ||
44 | - */ | ||
45 | - INTERNET, | ||
46 | - /** | ||
47 | - * There is no route for this IP address or IP prefix. | ||
48 | - */ | ||
49 | - NO_ROUTE | ||
50 | - } | ||
51 | - | ||
52 | - /** | ||
53 | - * Specifies the type of traffic. | ||
54 | - * <p> | ||
55 | - * We classify traffic by the first packet of each traffic. | ||
56 | - * </p> | ||
57 | - */ | ||
58 | - enum TrafficType { | ||
59 | - /** | ||
60 | - * Traffic from a host located in local SDN network wants to | ||
61 | - * communicate with destination host located in Internet (outside | ||
62 | - * local SDN network). | ||
63 | - */ | ||
64 | - HOST_TO_INTERNET, | ||
65 | - /** | ||
66 | - * Traffic from Internet wants to communicate with a host located | ||
67 | - * in local SDN network. | ||
68 | - */ | ||
69 | - INTERNET_TO_HOST, | ||
70 | - /** | ||
71 | - * Both the source host and destination host of a traffic are in | ||
72 | - * local SDN network. | ||
73 | - */ | ||
74 | - HOST_TO_HOST, | ||
75 | - /** | ||
76 | - * Traffic from Internet wants to traverse local SDN network. | ||
77 | - */ | ||
78 | - INTERNET_TO_INTERNET, | ||
79 | - /** | ||
80 | - * Any traffic wants to communicate with a destination which has | ||
81 | - * no route, or traffic from Internet wants to access a local private | ||
82 | - * IP address. | ||
83 | - */ | ||
84 | - DROP, | ||
85 | - /** | ||
86 | - * Traffic does not belong to the types above. | ||
87 | - */ | ||
88 | - UNKNOWN | ||
89 | - } | ||
90 | - | ||
91 | - /** | ||
92 | * Starts the routing service. | 33 | * Starts the routing service. |
93 | */ | 34 | */ |
94 | void start(); | 35 | void start(); |
... | @@ -101,15 +42,6 @@ public interface RoutingService { | ... | @@ -101,15 +42,6 @@ public interface RoutingService { |
101 | void addFibListener(FibListener fibListener); | 42 | void addFibListener(FibListener fibListener); |
102 | 43 | ||
103 | /** | 44 | /** |
104 | - * Adds intent creation and submission listener. | ||
105 | - * | ||
106 | - * @param intentRequestListener listener to send intent creation and | ||
107 | - * submission request to | ||
108 | - */ | ||
109 | - void addIntentRequestListener(IntentRequestListener | ||
110 | - intentRequestListener); | ||
111 | - | ||
112 | - /** | ||
113 | * Stops the routing service. | 45 | * Stops the routing service. |
114 | */ | 46 | */ |
115 | void stop(); | 47 | void stop(); |
... | @@ -129,14 +61,6 @@ public interface RoutingService { | ... | @@ -129,14 +61,6 @@ public interface RoutingService { |
129 | Collection<RouteEntry> getRoutes6(); | 61 | Collection<RouteEntry> getRoutes6(); |
130 | 62 | ||
131 | /** | 63 | /** |
132 | - * Evaluates the location of an IP address and returns the location type. | ||
133 | - * | ||
134 | - * @param ipAddress the IP address to evaluate | ||
135 | - * @return the IP address location type | ||
136 | - */ | ||
137 | - LocationType getLocationType(IpAddress ipAddress); | ||
138 | - | ||
139 | - /** | ||
140 | * Finds out the route entry which has the longest matchable IP prefix. | 64 | * Finds out the route entry which has the longest matchable IP prefix. |
141 | * | 65 | * |
142 | * @param ipAddress IP address used to find out longest matchable IP prefix | 66 | * @param ipAddress IP address used to find out longest matchable IP prefix |
... | @@ -145,25 +69,4 @@ public interface RoutingService { | ... | @@ -145,25 +69,4 @@ public interface RoutingService { |
145 | */ | 69 | */ |
146 | RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress); | 70 | RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress); |
147 | 71 | ||
148 | - /** | ||
149 | - * Finds out the egress connect point where to emit the first packet | ||
150 | - * based on destination IP address. | ||
151 | - * | ||
152 | - * @param dstIpAddress the destination IP address | ||
153 | - * @return the egress connect point if found, otherwise null | ||
154 | - */ | ||
155 | - ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress); | ||
156 | - | ||
157 | - /** | ||
158 | - * Routes packet reactively. | ||
159 | - * | ||
160 | - * @param dstIpAddress the destination IP address of a packet | ||
161 | - * @param srcIpAddress the source IP address of a packet | ||
162 | - * @param srcConnectPoint the connect point where a packet comes from | ||
163 | - * @param srcMacAddress the source MAC address of a packet | ||
164 | - */ | ||
165 | - void packetReactiveProcessor(IpAddress dstIpAddress, | ||
166 | - IpAddress srcIpAddress, | ||
167 | - ConnectPoint srcConnectPoint, | ||
168 | - MacAddress srcMacAddress); | ||
169 | } | 72 | } | ... | ... |
... | @@ -13,7 +13,7 @@ | ... | @@ -13,7 +13,7 @@ |
13 | * See the License for the specific language governing permissions and | 13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | -package org.onosproject.sdnip; | 16 | +package org.onosproject.routing; |
17 | 17 | ||
18 | /** | 18 | /** |
19 | * Service interface exported by SDN-IP. | 19 | * Service interface exported by SDN-IP. |
... | @@ -28,4 +28,12 @@ public interface SdnIpService { | ... | @@ -28,4 +28,12 @@ public interface SdnIpService { |
28 | */ | 28 | */ |
29 | void modifyPrimary(boolean isPrimary); | 29 | void modifyPrimary(boolean isPrimary); |
30 | 30 | ||
31 | + /** | ||
32 | + * Gets the intent synchronization service. | ||
33 | + * | ||
34 | + * @return intent synchronization service | ||
35 | + */ | ||
36 | + // TODO fix service resolution in SDN-IP | ||
37 | + IntentSynchronizationService getIntentSynchronizationService(); | ||
38 | + | ||
31 | } | 39 | } | ... | ... |
... | @@ -35,9 +35,7 @@ import org.onlab.packet.IpAddress; | ... | @@ -35,9 +35,7 @@ import org.onlab.packet.IpAddress; |
35 | import org.onlab.packet.IpPrefix; | 35 | import org.onlab.packet.IpPrefix; |
36 | import org.onlab.packet.MacAddress; | 36 | import org.onlab.packet.MacAddress; |
37 | import org.onosproject.core.CoreService; | 37 | import org.onosproject.core.CoreService; |
38 | -import org.onosproject.incubator.net.intf.Interface; | ||
39 | import org.onosproject.incubator.net.intf.InterfaceService; | 38 | import org.onosproject.incubator.net.intf.InterfaceService; |
40 | -import org.onosproject.net.ConnectPoint; | ||
41 | import org.onosproject.net.Host; | 39 | import org.onosproject.net.Host; |
42 | import org.onosproject.net.host.HostEvent; | 40 | import org.onosproject.net.host.HostEvent; |
43 | import org.onosproject.net.host.HostListener; | 41 | import org.onosproject.net.host.HostListener; |
... | @@ -46,7 +44,6 @@ import org.onosproject.routing.BgpService; | ... | @@ -46,7 +44,6 @@ import org.onosproject.routing.BgpService; |
46 | import org.onosproject.routing.FibEntry; | 44 | import org.onosproject.routing.FibEntry; |
47 | import org.onosproject.routing.FibListener; | 45 | import org.onosproject.routing.FibListener; |
48 | import org.onosproject.routing.FibUpdate; | 46 | import org.onosproject.routing.FibUpdate; |
49 | -import org.onosproject.routing.IntentRequestListener; | ||
50 | import org.onosproject.routing.RouteEntry; | 47 | import org.onosproject.routing.RouteEntry; |
51 | import org.onosproject.routing.RouteListener; | 48 | import org.onosproject.routing.RouteListener; |
52 | import org.onosproject.routing.RouteUpdate; | 49 | import org.onosproject.routing.RouteUpdate; |
... | @@ -61,7 +58,6 @@ import java.util.Iterator; | ... | @@ -61,7 +58,6 @@ import java.util.Iterator; |
61 | import java.util.LinkedList; | 58 | import java.util.LinkedList; |
62 | import java.util.List; | 59 | import java.util.List; |
63 | import java.util.Map; | 60 | import java.util.Map; |
64 | -import java.util.Optional; | ||
65 | import java.util.Set; | 61 | import java.util.Set; |
66 | import java.util.concurrent.BlockingQueue; | 62 | import java.util.concurrent.BlockingQueue; |
67 | import java.util.concurrent.ConcurrentHashMap; | 63 | import java.util.concurrent.ConcurrentHashMap; |
... | @@ -100,7 +96,6 @@ public class Router implements RoutingService { | ... | @@ -100,7 +96,6 @@ public class Router implements RoutingService { |
100 | private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>(); | 96 | private final Map<IpAddress, MacAddress> ip2Mac = new ConcurrentHashMap<>(); |
101 | 97 | ||
102 | private FibListener fibComponent; | 98 | private FibListener fibComponent; |
103 | - private IntentRequestListener intentRequestListener; | ||
104 | 99 | ||
105 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) | 100 | @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) |
106 | protected CoreService coreService; | 101 | protected CoreService coreService; |
... | @@ -145,12 +140,6 @@ public class Router implements RoutingService { | ... | @@ -145,12 +140,6 @@ public class Router implements RoutingService { |
145 | @Override | 140 | @Override |
146 | public void addFibListener(FibListener fibListener) { | 141 | public void addFibListener(FibListener fibListener) { |
147 | this.fibComponent = checkNotNull(fibListener); | 142 | this.fibComponent = checkNotNull(fibListener); |
148 | - | ||
149 | - } | ||
150 | - | ||
151 | - @Override | ||
152 | - public void addIntentRequestListener(IntentRequestListener intentRequestListener) { | ||
153 | - this.intentRequestListener = checkNotNull(intentRequestListener); | ||
154 | } | 143 | } |
155 | 144 | ||
156 | @Override | 145 | @Override |
... | @@ -287,12 +276,10 @@ public class Router implements RoutingService { | ... | @@ -287,12 +276,10 @@ public class Router implements RoutingService { |
287 | void addRibRoute(RouteEntry routeEntry) { | 276 | void addRibRoute(RouteEntry routeEntry) { |
288 | if (routeEntry.isIp4()) { | 277 | if (routeEntry.isIp4()) { |
289 | // IPv4 | 278 | // IPv4 |
290 | - ribTable4.put(createBinaryString(routeEntry.prefix()), | 279 | + ribTable4.put(createBinaryString(routeEntry.prefix()), routeEntry); |
291 | - routeEntry); | ||
292 | } else { | 280 | } else { |
293 | // IPv6 | 281 | // IPv6 |
294 | - ribTable6.put(createBinaryString(routeEntry.prefix()), | 282 | + ribTable6.put(createBinaryString(routeEntry.prefix()), routeEntry); |
295 | - routeEntry); | ||
296 | } | 283 | } |
297 | } | 284 | } |
298 | 285 | ||
... | @@ -553,17 +540,6 @@ public class Router implements RoutingService { | ... | @@ -553,17 +540,6 @@ public class Router implements RoutingService { |
553 | } | 540 | } |
554 | 541 | ||
555 | @Override | 542 | @Override |
556 | - public LocationType getLocationType(IpAddress ipAddress) { | ||
557 | - if (routingConfigurationService.isIpAddressLocal(ipAddress)) { | ||
558 | - return LocationType.LOCAL; | ||
559 | - } else if (getLongestMatchableRouteEntry(ipAddress) != null) { | ||
560 | - return LocationType.INTERNET; | ||
561 | - } else { | ||
562 | - return LocationType.NO_ROUTE; | ||
563 | - } | ||
564 | - } | ||
565 | - | ||
566 | - @Override | ||
567 | public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) { | 543 | public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) { |
568 | RouteEntry routeEntry = null; | 544 | RouteEntry routeEntry = null; |
569 | Iterable<RouteEntry> routeEntries; | 545 | Iterable<RouteEntry> routeEntries; |
... | @@ -587,142 +563,4 @@ public class Router implements RoutingService { | ... | @@ -587,142 +563,4 @@ public class Router implements RoutingService { |
587 | return routeEntry; | 563 | return routeEntry; |
588 | } | 564 | } |
589 | 565 | ||
590 | - @Override | ||
591 | - public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) { | ||
592 | - LocationType type = getLocationType(dstIpAddress); | ||
593 | - if (type == LocationType.LOCAL) { | ||
594 | - Set<Host> hosts = hostService.getHostsByIp(dstIpAddress); | ||
595 | - if (!hosts.isEmpty()) { | ||
596 | - return hosts.iterator().next().location(); | ||
597 | - } else { | ||
598 | - hostService.startMonitoringIp(dstIpAddress); | ||
599 | - return null; | ||
600 | - } | ||
601 | - } else if (type == LocationType.INTERNET) { | ||
602 | - IpAddress nextHopIpAddress = null; | ||
603 | - RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress); | ||
604 | - if (routeEntry != null) { | ||
605 | - nextHopIpAddress = routeEntry.nextHop(); | ||
606 | - Interface it = interfaceService.getMatchingInterface(nextHopIpAddress); | ||
607 | - if (it != null) { | ||
608 | - return it.connectPoint(); | ||
609 | - } else { | ||
610 | - return null; | ||
611 | - } | ||
612 | - } else { | ||
613 | - return null; | ||
614 | - } | ||
615 | - } else { | ||
616 | - return null; | ||
617 | - } | ||
618 | - } | ||
619 | - | ||
620 | - @Override | ||
621 | - public void packetReactiveProcessor(IpAddress dstIpAddress, | ||
622 | - IpAddress srcIpAddress, | ||
623 | - ConnectPoint srcConnectPoint, | ||
624 | - MacAddress srcMacAddress) { | ||
625 | - checkNotNull(dstIpAddress); | ||
626 | - checkNotNull(srcIpAddress); | ||
627 | - checkNotNull(srcConnectPoint); | ||
628 | - checkNotNull(srcMacAddress); | ||
629 | - | ||
630 | - // | ||
631 | - // Step1: Try to update the existing intent first if it exists. | ||
632 | - // | ||
633 | - IpPrefix ipPrefix = null; | ||
634 | - if (routingConfigurationService.isIpAddressLocal(dstIpAddress)) { | ||
635 | - if (dstIpAddress.isIp4()) { | ||
636 | - ipPrefix = IpPrefix.valueOf(dstIpAddress, | ||
637 | - Ip4Address.BIT_LENGTH); | ||
638 | - } else { | ||
639 | - ipPrefix = IpPrefix.valueOf(dstIpAddress, | ||
640 | - Ip6Address.BIT_LENGTH); | ||
641 | - } | ||
642 | - } else { | ||
643 | - // Get IP prefix from BGP route table | ||
644 | - RouteEntry routeEntry = getLongestMatchableRouteEntry(dstIpAddress); | ||
645 | - if (routeEntry != null) { | ||
646 | - ipPrefix = routeEntry.prefix(); | ||
647 | - } | ||
648 | - } | ||
649 | - if (ipPrefix != null | ||
650 | - && intentRequestListener.mp2pIntentExists(ipPrefix)) { | ||
651 | - intentRequestListener.updateExistingMp2pIntent(ipPrefix, | ||
652 | - srcConnectPoint); | ||
653 | - return; | ||
654 | - } | ||
655 | - | ||
656 | - // | ||
657 | - // Step2: There is no existing intent for the destination IP address. | ||
658 | - // Check whether it is necessary to create a new one. If necessary then | ||
659 | - // create a new one. | ||
660 | - // | ||
661 | - TrafficType trafficType = | ||
662 | - trafficTypeClassifier(srcConnectPoint, dstIpAddress); | ||
663 | - | ||
664 | - switch (trafficType) { | ||
665 | - case HOST_TO_INTERNET: | ||
666 | - // If the destination IP address is outside the local SDN network. | ||
667 | - // The Step 1 has already handled it. We do not need to do anything here. | ||
668 | - break; | ||
669 | - case INTERNET_TO_HOST: | ||
670 | - intentRequestListener.setUpConnectivityInternetToHost(dstIpAddress); | ||
671 | - break; | ||
672 | - case HOST_TO_HOST: | ||
673 | - intentRequestListener.setUpConnectivityHostToHost(dstIpAddress, | ||
674 | - srcIpAddress, srcMacAddress, srcConnectPoint); | ||
675 | - break; | ||
676 | - case INTERNET_TO_INTERNET: | ||
677 | - log.trace("This is transit traffic, " | ||
678 | - + "the intent should be preinstalled already"); | ||
679 | - break; | ||
680 | - case DROP: | ||
681 | - // TODO here should setUpDropPaccketIntent(...); | ||
682 | - // We need a new type of intent here. | ||
683 | - break; | ||
684 | - case UNKNOWN: | ||
685 | - log.trace("This is unknown traffic, so we do nothing"); | ||
686 | - break; | ||
687 | - default: | ||
688 | - break; | ||
689 | - } | ||
690 | - } | ||
691 | - | ||
692 | - /** | ||
693 | - * Classifies the traffic and return the traffic type. | ||
694 | - * | ||
695 | - * @param srcConnectPoint the connect point where the packet comes from | ||
696 | - * @param dstIp the destination IP address in packet | ||
697 | - * @return the traffic type which this packet belongs to | ||
698 | - */ | ||
699 | - private TrafficType trafficTypeClassifier(ConnectPoint srcConnectPoint, | ||
700 | - IpAddress dstIp) { | ||
701 | - LocationType dstIpLocationType = getLocationType(dstIp); | ||
702 | - Optional<Interface> srcInterface = | ||
703 | - interfaceService.getInterfacesByPort(srcConnectPoint).stream().findFirst(); | ||
704 | - | ||
705 | - switch (dstIpLocationType) { | ||
706 | - case INTERNET: | ||
707 | - if (!srcInterface.isPresent()) { | ||
708 | - return TrafficType.HOST_TO_INTERNET; | ||
709 | - } else { | ||
710 | - return TrafficType.INTERNET_TO_INTERNET; | ||
711 | - } | ||
712 | - case LOCAL: | ||
713 | - if (!srcInterface.isPresent()) { | ||
714 | - return TrafficType.HOST_TO_HOST; | ||
715 | - } else { | ||
716 | - // TODO Currently we only consider local public prefixes. | ||
717 | - // In the future, we will consider the local private prefixes. | ||
718 | - // If dstIpLocationType is a local private, we should return | ||
719 | - // TrafficType.DROP. | ||
720 | - return TrafficType.INTERNET_TO_HOST; | ||
721 | - } | ||
722 | - case NO_ROUTE: | ||
723 | - return TrafficType.DROP; | ||
724 | - default: | ||
725 | - return TrafficType.UNKNOWN; | ||
726 | - } | ||
727 | - } | ||
728 | } | 566 | } | ... | ... |
... | @@ -18,10 +18,7 @@ package org.onosproject.routing.impl; | ... | @@ -18,10 +18,7 @@ package org.onosproject.routing.impl; |
18 | import org.apache.felix.scr.annotations.Component; | 18 | import org.apache.felix.scr.annotations.Component; |
19 | import org.apache.felix.scr.annotations.Service; | 19 | import org.apache.felix.scr.annotations.Service; |
20 | import org.onlab.packet.IpAddress; | 20 | import org.onlab.packet.IpAddress; |
21 | -import org.onlab.packet.MacAddress; | ||
22 | -import org.onosproject.net.ConnectPoint; | ||
23 | import org.onosproject.routing.FibListener; | 21 | import org.onosproject.routing.FibListener; |
24 | -import org.onosproject.routing.IntentRequestListener; | ||
25 | import org.onosproject.routing.RouteEntry; | 22 | import org.onosproject.routing.RouteEntry; |
26 | import org.onosproject.routing.RoutingService; | 23 | import org.onosproject.routing.RoutingService; |
27 | import org.onosproject.routing.StaticRoutingService; | 24 | import org.onosproject.routing.StaticRoutingService; |
... | @@ -49,11 +46,6 @@ public class StaticRouter implements RoutingService, StaticRoutingService { | ... | @@ -49,11 +46,6 @@ public class StaticRouter implements RoutingService, StaticRoutingService { |
49 | } | 46 | } |
50 | 47 | ||
51 | @Override | 48 | @Override |
52 | - public void addIntentRequestListener(IntentRequestListener intentRequestListener) { | ||
53 | - | ||
54 | - } | ||
55 | - | ||
56 | - @Override | ||
57 | public void stop() { | 49 | public void stop() { |
58 | 50 | ||
59 | } | 51 | } |
... | @@ -69,27 +61,11 @@ public class StaticRouter implements RoutingService, StaticRoutingService { | ... | @@ -69,27 +61,11 @@ public class StaticRouter implements RoutingService, StaticRoutingService { |
69 | } | 61 | } |
70 | 62 | ||
71 | @Override | 63 | @Override |
72 | - public LocationType getLocationType(IpAddress ipAddress) { | ||
73 | - return null; | ||
74 | - } | ||
75 | - | ||
76 | - @Override | ||
77 | public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) { | 64 | public RouteEntry getLongestMatchableRouteEntry(IpAddress ipAddress) { |
78 | return null; | 65 | return null; |
79 | } | 66 | } |
80 | 67 | ||
81 | @Override | 68 | @Override |
82 | - public ConnectPoint getEgressConnectPoint(IpAddress dstIpAddress) { | ||
83 | - return null; | ||
84 | - } | ||
85 | - | ||
86 | - @Override | ||
87 | - public void packetReactiveProcessor(IpAddress dstIpAddress, IpAddress srcIpAddress, | ||
88 | - ConnectPoint srcConnectPoint, MacAddress srcMacAddress) { | ||
89 | - | ||
90 | - } | ||
91 | - | ||
92 | - @Override | ||
93 | public FibListener getFibListener() { | 69 | public FibListener getFibListener() { |
94 | return fibListener; | 70 | return fibListener; |
95 | } | 71 | } | ... | ... |
... | @@ -15,118 +15,79 @@ | ... | @@ -15,118 +15,79 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.sdnip; | 16 | package org.onosproject.sdnip; |
17 | 17 | ||
18 | -import com.google.common.collect.ImmutableList; | ||
19 | -import com.google.common.util.concurrent.ThreadFactoryBuilder; | ||
20 | -import org.onlab.packet.Ethernet; | ||
21 | -import org.onlab.packet.IpAddress; | ||
22 | -import org.onlab.packet.IpPrefix; | ||
23 | -import org.onlab.packet.MacAddress; | ||
24 | -import org.onlab.packet.VlanId; | ||
25 | import org.onosproject.core.ApplicationId; | 18 | import org.onosproject.core.ApplicationId; |
26 | -import org.onosproject.incubator.net.intf.Interface; | ||
27 | -import org.onosproject.incubator.net.intf.InterfaceService; | ||
28 | -import org.onosproject.net.ConnectPoint; | ||
29 | -import org.onosproject.net.Host; | ||
30 | -import org.onosproject.net.flow.DefaultTrafficSelector; | ||
31 | -import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
32 | -import org.onosproject.net.flow.TrafficSelector; | ||
33 | -import org.onosproject.net.flow.TrafficTreatment; | ||
34 | -import org.onosproject.net.flow.criteria.Criterion; | ||
35 | -import org.onosproject.net.flow.criteria.IPCriterion; | ||
36 | -import org.onosproject.net.host.HostService; | ||
37 | -import org.onosproject.net.intent.Constraint; | ||
38 | import org.onosproject.net.intent.Intent; | 19 | import org.onosproject.net.intent.Intent; |
39 | import org.onosproject.net.intent.IntentService; | 20 | import org.onosproject.net.intent.IntentService; |
40 | import org.onosproject.net.intent.IntentState; | 21 | import org.onosproject.net.intent.IntentState; |
41 | import org.onosproject.net.intent.Key; | 22 | import org.onosproject.net.intent.Key; |
42 | -import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 23 | +import org.onosproject.routing.IntentSynchronizationService; |
43 | -import org.onosproject.net.intent.PointToPointIntent; | ||
44 | -import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
45 | -import org.onosproject.routing.FibListener; | ||
46 | -import org.onosproject.routing.FibUpdate; | ||
47 | -import org.onosproject.routing.IntentRequestListener; | ||
48 | -import org.onosproject.routing.config.RoutingConfigurationService; | ||
49 | import org.slf4j.Logger; | 24 | import org.slf4j.Logger; |
50 | import org.slf4j.LoggerFactory; | 25 | import org.slf4j.LoggerFactory; |
51 | 26 | ||
52 | -import java.util.Collection; | ||
53 | import java.util.HashMap; | 27 | import java.util.HashMap; |
54 | -import java.util.HashSet; | ||
55 | import java.util.LinkedList; | 28 | import java.util.LinkedList; |
56 | import java.util.List; | 29 | import java.util.List; |
57 | import java.util.Map; | 30 | import java.util.Map; |
58 | -import java.util.Objects; | ||
59 | -import java.util.Set; | ||
60 | import java.util.concurrent.ConcurrentHashMap; | 31 | import java.util.concurrent.ConcurrentHashMap; |
61 | import java.util.concurrent.ExecutorService; | 32 | import java.util.concurrent.ExecutorService; |
62 | -import java.util.concurrent.Executors; | ||
63 | -import java.util.concurrent.Semaphore; | ||
64 | 33 | ||
65 | -import static com.google.common.base.Preconditions.checkArgument; | 34 | +import static java.util.concurrent.Executors.newSingleThreadExecutor; |
66 | -import static com.google.common.base.Preconditions.checkNotNull; | 35 | +import static org.onlab.util.Tools.groupedThreads; |
67 | 36 | ||
68 | /** | 37 | /** |
69 | * Synchronizes intents between the in-memory intent store and the | 38 | * Synchronizes intents between the in-memory intent store and the |
70 | * IntentService. | 39 | * IntentService. |
71 | */ | 40 | */ |
72 | -public class IntentSynchronizer implements FibListener, IntentRequestListener { | 41 | +public class IntentSynchronizer implements IntentSynchronizationService { |
73 | - private static final int PRIORITY_OFFSET = 100; | ||
74 | - private static final int PRIORITY_MULTIPLIER = 5; | ||
75 | - protected static final ImmutableList<Constraint> CONSTRAINTS | ||
76 | - = ImmutableList.of(new PartialFailureConstraint()); | ||
77 | 42 | ||
78 | private static final Logger log = | 43 | private static final Logger log = |
79 | LoggerFactory.getLogger(IntentSynchronizer.class); | 44 | LoggerFactory.getLogger(IntentSynchronizer.class); |
80 | 45 | ||
81 | private final ApplicationId appId; | 46 | private final ApplicationId appId; |
82 | private final IntentService intentService; | 47 | private final IntentService intentService; |
83 | - private final HostService hostService; | 48 | + |
84 | - private final InterfaceService interfaceService; | 49 | + private final Map<Key, Intent> intents; |
85 | - private final Map<IntentKey, PointToPointIntent> peerIntents; | ||
86 | - private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents; | ||
87 | 50 | ||
88 | // | 51 | // |
89 | // State to deal with SDN-IP Leader election and pushing Intents | 52 | // State to deal with SDN-IP Leader election and pushing Intents |
90 | // | 53 | // |
91 | private final ExecutorService bgpIntentsSynchronizerExecutor; | 54 | private final ExecutorService bgpIntentsSynchronizerExecutor; |
92 | - private final Semaphore intentsSynchronizerSemaphore = new Semaphore(0); | ||
93 | private volatile boolean isElectedLeader = false; | 55 | private volatile boolean isElectedLeader = false; |
94 | private volatile boolean isActivatedLeader = false; | 56 | private volatile boolean isActivatedLeader = false; |
95 | 57 | ||
96 | - private final RoutingConfigurationService configService; | 58 | + /** |
59 | + * Class constructor. | ||
60 | + * | ||
61 | + * @param appId the Application ID | ||
62 | + * @param intentService the intent service | ||
63 | + */ | ||
64 | + IntentSynchronizer(ApplicationId appId, IntentService intentService) { | ||
65 | + this(appId, intentService, | ||
66 | + newSingleThreadExecutor(groupedThreads("onos/sdnip", "sync"))); | ||
67 | + } | ||
97 | 68 | ||
98 | /** | 69 | /** |
99 | * Class constructor. | 70 | * Class constructor. |
100 | * | 71 | * |
101 | * @param appId the Application ID | 72 | * @param appId the Application ID |
102 | * @param intentService the intent service | 73 | * @param intentService the intent service |
103 | - * @param hostService the host service | 74 | + * @param executorService executor service for synchronization thread |
104 | - * @param configService the SDN-IP configuration service | ||
105 | - * @param interfaceService the interface service | ||
106 | */ | 75 | */ |
107 | IntentSynchronizer(ApplicationId appId, IntentService intentService, | 76 | IntentSynchronizer(ApplicationId appId, IntentService intentService, |
108 | - HostService hostService, | 77 | + ExecutorService executorService) { |
109 | - RoutingConfigurationService configService, | ||
110 | - InterfaceService interfaceService) { | ||
111 | this.appId = appId; | 78 | this.appId = appId; |
112 | this.intentService = intentService; | 79 | this.intentService = intentService; |
113 | - this.hostService = hostService; | ||
114 | - this.interfaceService = interfaceService; | ||
115 | - peerIntents = new ConcurrentHashMap<>(); | ||
116 | - routeIntents = new ConcurrentHashMap<>(); | ||
117 | 80 | ||
118 | - this.configService = configService; | 81 | + intents = new ConcurrentHashMap<>(); |
119 | 82 | ||
120 | - bgpIntentsSynchronizerExecutor = Executors.newSingleThreadExecutor( | 83 | + bgpIntentsSynchronizerExecutor = executorService; |
121 | - new ThreadFactoryBuilder() | ||
122 | - .setNameFormat("sdnip-intents-synchronizer-%d").build()); | ||
123 | } | 84 | } |
124 | 85 | ||
125 | /** | 86 | /** |
126 | * Starts the synchronizer. | 87 | * Starts the synchronizer. |
127 | */ | 88 | */ |
128 | public void start() { | 89 | public void start() { |
129 | - bgpIntentsSynchronizerExecutor.execute(this::doIntentSynchronizationThread); | 90 | + |
130 | } | 91 | } |
131 | 92 | ||
132 | /** | 93 | /** |
... | @@ -187,419 +148,107 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -187,419 +148,107 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
187 | } | 148 | } |
188 | } | 149 | } |
189 | 150 | ||
190 | - /** | 151 | + @Override |
191 | - * Signals the synchronizer that the SDN-IP leadership has changed. | 152 | + public void submit(Intent intent) { |
192 | - * | ||
193 | - * @param isLeader true if this instance is now the leader, otherwise false | ||
194 | - */ | ||
195 | - public void leaderChanged(boolean isLeader) { | ||
196 | - log.debug("SDN-IP Leader changed: {}", isLeader); | ||
197 | - | ||
198 | - if (!isLeader) { | ||
199 | - this.isElectedLeader = false; | ||
200 | - this.isActivatedLeader = false; | ||
201 | - return; // Nothing to do | ||
202 | - } | ||
203 | - this.isActivatedLeader = false; | ||
204 | - this.isElectedLeader = true; | ||
205 | - | ||
206 | - // | ||
207 | - // Tell the Intents Synchronizer thread to start the synchronization | ||
208 | - // | ||
209 | - intentsSynchronizerSemaphore.release(); | ||
210 | - } | ||
211 | - | ||
212 | - /** | ||
213 | - * Gets the route intents. | ||
214 | - * | ||
215 | - * @return the route intents | ||
216 | - */ | ||
217 | - public Collection<MultiPointToSinglePointIntent> getRouteIntents() { | ||
218 | - List<MultiPointToSinglePointIntent> result = new LinkedList<>(); | ||
219 | - | ||
220 | - for (Map.Entry<IpPrefix, MultiPointToSinglePointIntent> entry : | ||
221 | - routeIntents.entrySet()) { | ||
222 | - result.add(entry.getValue()); | ||
223 | - } | ||
224 | - return result; | ||
225 | - } | ||
226 | - | ||
227 | - /** | ||
228 | - * Thread for Intent Synchronization. | ||
229 | - */ | ||
230 | - private void doIntentSynchronizationThread() { | ||
231 | - boolean interrupted = false; | ||
232 | - try { | ||
233 | - while (!interrupted) { | ||
234 | - try { | ||
235 | - intentsSynchronizerSemaphore.acquire(); | ||
236 | - // | ||
237 | - // Drain all permits, because a single synchronization is | ||
238 | - // sufficient. | ||
239 | - // | ||
240 | - intentsSynchronizerSemaphore.drainPermits(); | ||
241 | - } catch (InterruptedException e) { | ||
242 | - interrupted = true; | ||
243 | - break; | ||
244 | - } | ||
245 | - synchronizeIntents(); | ||
246 | - } | ||
247 | - } finally { | ||
248 | - if (interrupted) { | ||
249 | - Thread.currentThread().interrupt(); | ||
250 | - } | ||
251 | - } | ||
252 | - } | ||
253 | - | ||
254 | - /** | ||
255 | - * Submits a collection of point-to-point intents. | ||
256 | - * | ||
257 | - * @param intents the intents to submit | ||
258 | - */ | ||
259 | - void submitPeerIntents(Collection<PointToPointIntent> intents) { | ||
260 | synchronized (this) { | 153 | synchronized (this) { |
261 | - // Store the intents in memory | 154 | + intents.put(intent.key(), intent); |
262 | - for (PointToPointIntent intent : intents) { | ||
263 | - peerIntents.put(new IntentKey(intent), intent); | ||
264 | - } | ||
265 | - | ||
266 | - // Push the intents | ||
267 | if (isElectedLeader && isActivatedLeader) { | 155 | if (isElectedLeader && isActivatedLeader) { |
268 | - log.debug("SDN-IP Submitting all Peer Intents..."); | 156 | + log.trace("SDN-IP Submitting intent: {}", intent); |
269 | - for (Intent intent : intents) { | ||
270 | - log.trace("SDN-IP Submitting intents: {}", intent); | ||
271 | intentService.submit(intent); | 157 | intentService.submit(intent); |
272 | } | 158 | } |
273 | } | 159 | } |
274 | } | 160 | } |
275 | - } | ||
276 | 161 | ||
277 | - /** | 162 | + @Override |
278 | - * Submits a MultiPointToSinglePointIntent for reactive routing. | 163 | + public void withdraw(Intent intent) { |
279 | - * | ||
280 | - * @param ipPrefix the IP prefix to match in a MultiPointToSinglePointIntent | ||
281 | - * @param intent the intent to submit | ||
282 | - */ | ||
283 | - void submitReactiveIntent(IpPrefix ipPrefix, MultiPointToSinglePointIntent intent) { | ||
284 | synchronized (this) { | 164 | synchronized (this) { |
285 | - // Store the intent in memory | 165 | + intents.remove(intent.key(), intent); |
286 | - routeIntents.put(ipPrefix, intent); | ||
287 | - | ||
288 | - // Push the intent | ||
289 | if (isElectedLeader && isActivatedLeader) { | 166 | if (isElectedLeader && isActivatedLeader) { |
290 | - log.trace("SDN-IP submitting reactive routing intent: {}", intent); | 167 | + log.trace("SDN-IP Withdrawing intent: {}", intent); |
291 | - intentService.submit(intent); | 168 | + intentService.withdraw(intent); |
292 | } | 169 | } |
293 | } | 170 | } |
294 | } | 171 | } |
295 | 172 | ||
296 | /** | 173 | /** |
297 | - * Generates a route intent for a prefix, the next hop IP address, and | 174 | + * Signals the synchronizer that the SDN-IP leadership has changed. |
298 | - * the next hop MAC address. | ||
299 | - * <p/> | ||
300 | - * This method will find the egress interface for the intent. | ||
301 | - * Intent will match dst IP prefix and rewrite dst MAC address at all other | ||
302 | - * border switches, then forward packets according to dst MAC address. | ||
303 | * | 175 | * |
304 | - * @param prefix IP prefix of the route to add | 176 | + * @param isLeader true if this instance is now the leader, otherwise false |
305 | - * @param nextHopIpAddress IP address of the next hop | ||
306 | - * @param nextHopMacAddress MAC address of the next hop | ||
307 | - * @return the generated intent, or null if no intent should be submitted | ||
308 | */ | 177 | */ |
309 | - private MultiPointToSinglePointIntent generateRouteIntent( | 178 | + public void leaderChanged(boolean isLeader) { |
310 | - IpPrefix prefix, | 179 | + log.debug("SDN-IP Leader changed: {}", isLeader); |
311 | - IpAddress nextHopIpAddress, | ||
312 | - MacAddress nextHopMacAddress) { | ||
313 | - | ||
314 | - // Find the attachment point (egress interface) of the next hop | ||
315 | - Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress); | ||
316 | - if (egressInterface == null) { | ||
317 | - log.warn("No outgoing interface found for {}", | ||
318 | - nextHopIpAddress); | ||
319 | - return null; | ||
320 | - } | ||
321 | - | ||
322 | - // | ||
323 | - // Generate the intent itself | ||
324 | - // | ||
325 | - Set<ConnectPoint> ingressPorts = new HashSet<>(); | ||
326 | - ConnectPoint egressPort = egressInterface.connectPoint(); | ||
327 | - log.debug("Generating intent for prefix {}, next hop mac {}", | ||
328 | - prefix, nextHopMacAddress); | ||
329 | - | ||
330 | - for (Interface intf : interfaceService.getInterfaces()) { | ||
331 | - // TODO this should be only peering interfaces | ||
332 | - if (!intf.connectPoint().equals(egressInterface.connectPoint())) { | ||
333 | - ConnectPoint srcPort = intf.connectPoint(); | ||
334 | - ingressPorts.add(srcPort); | ||
335 | - } | ||
336 | - } | ||
337 | 180 | ||
338 | - // Match the destination IP prefix at the first hop | 181 | + if (!isLeader) { |
339 | - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | 182 | + this.isElectedLeader = false; |
340 | - if (prefix.isIp4()) { | 183 | + this.isActivatedLeader = false; |
341 | - selector.matchEthType(Ethernet.TYPE_IPV4); | 184 | + return; // Nothing to do |
342 | - selector.matchIPDst(prefix); | ||
343 | - } else { | ||
344 | - selector.matchEthType(Ethernet.TYPE_IPV6); | ||
345 | - selector.matchIPv6Dst(prefix); | ||
346 | } | 185 | } |
186 | + this.isActivatedLeader = false; | ||
187 | + this.isElectedLeader = true; | ||
347 | 188 | ||
348 | - // Rewrite the destination MAC address | 189 | + // Run the synchronization method off-thread |
349 | - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() | 190 | + bgpIntentsSynchronizerExecutor.execute(this::synchronizeIntents); |
350 | - .setEthDst(nextHopMacAddress); | ||
351 | - if (!egressInterface.vlan().equals(VlanId.NONE)) { | ||
352 | - treatment.setVlanId(egressInterface.vlan()); | ||
353 | - // If we set VLAN ID, we have to make sure a VLAN tag exists. | ||
354 | - // TODO support no VLAN -> VLAN routing | ||
355 | - selector.matchVlanId(VlanId.ANY); | ||
356 | } | 191 | } |
357 | 192 | ||
358 | - int priority = | 193 | + private void synchronizeIntents() { |
359 | - prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; | 194 | + Map<Key, Intent> serviceIntents = new HashMap<>(); |
360 | - Key key = Key.of(prefix.toString(), appId); | 195 | + intentService.getIntents().forEach(i -> { |
361 | - return MultiPointToSinglePointIntent.builder() | 196 | + if (i.appId().equals(appId)) { |
362 | - .appId(appId) | 197 | + serviceIntents.put(i.key(), i); |
363 | - .key(key) | ||
364 | - .selector(selector.build()) | ||
365 | - .treatment(treatment.build()) | ||
366 | - .ingressPoints(ingressPorts) | ||
367 | - .egressPoint(egressPort) | ||
368 | - .priority(priority) | ||
369 | - .constraints(CONSTRAINTS) | ||
370 | - .build(); | ||
371 | } | 198 | } |
199 | + }); | ||
372 | 200 | ||
373 | - @Override | 201 | + List<Intent> intentsToAdd = new LinkedList<>(); |
374 | - public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) { | 202 | + List<Intent> intentsToRemove = new LinkedList<>(); |
375 | - checkNotNull(hostIpAddress); | ||
376 | - Set<ConnectPoint> ingressPoints = | ||
377 | - configService.getBgpPeerConnectPoints(); | ||
378 | - | ||
379 | - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
380 | 203 | ||
381 | - if (hostIpAddress.isIp4()) { | 204 | + for (Intent localIntent : intents.values()) { |
382 | - selector.matchEthType(Ethernet.TYPE_IPV4); | 205 | + Intent serviceIntent = serviceIntents.remove(localIntent.key()); |
206 | + if (serviceIntent == null) { | ||
207 | + intentsToAdd.add(localIntent); | ||
383 | } else { | 208 | } else { |
384 | - selector.matchEthType(Ethernet.TYPE_IPV6); | 209 | + IntentState state = intentService.getIntentState(serviceIntent.key()); |
385 | - } | 210 | + if (!IntentUtils.equals(serviceIntent, localIntent) || state == null || |
386 | - | 211 | + state == IntentState.WITHDRAW_REQ || |
387 | - // Match the destination IP prefix at the first hop | 212 | + state == IntentState.WITHDRAWING || |
388 | - IpPrefix ipPrefix = hostIpAddress.toIpPrefix(); | 213 | + state == IntentState.WITHDRAWN) { |
389 | - selector.matchIPDst(ipPrefix); | 214 | + intentsToAdd.add(localIntent); |
390 | - | ||
391 | - // Rewrite the destination MAC address | ||
392 | - MacAddress hostMac = null; | ||
393 | - ConnectPoint egressPoint = null; | ||
394 | - for (Host host : hostService.getHostsByIp(hostIpAddress)) { | ||
395 | - if (host.mac() != null) { | ||
396 | - hostMac = host.mac(); | ||
397 | - egressPoint = host.location(); | ||
398 | - break; | ||
399 | - } | ||
400 | - } | ||
401 | - if (hostMac == null) { | ||
402 | - hostService.startMonitoringIp(hostIpAddress); | ||
403 | - return; | ||
404 | - } | ||
405 | - | ||
406 | - TrafficTreatment.Builder treatment = | ||
407 | - DefaultTrafficTreatment.builder().setEthDst(hostMac); | ||
408 | - Key key = Key.of(ipPrefix.toString(), appId); | ||
409 | - int priority = ipPrefix.prefixLength() * PRIORITY_MULTIPLIER | ||
410 | - + PRIORITY_OFFSET; | ||
411 | - MultiPointToSinglePointIntent intent = | ||
412 | - MultiPointToSinglePointIntent.builder() | ||
413 | - .appId(appId) | ||
414 | - .key(key) | ||
415 | - .selector(selector.build()) | ||
416 | - .treatment(treatment.build()) | ||
417 | - .ingressPoints(ingressPoints) | ||
418 | - .egressPoint(egressPoint) | ||
419 | - .priority(priority) | ||
420 | - .constraints(CONSTRAINTS) | ||
421 | - .build(); | ||
422 | - | ||
423 | - log.trace("Generates ConnectivityInternetToHost intent {}", intent); | ||
424 | - submitReactiveIntent(ipPrefix, intent); | ||
425 | - } | ||
426 | - | ||
427 | - | ||
428 | - @Override | ||
429 | - public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) { | ||
430 | - // | ||
431 | - // NOTE: Semantically, we MUST withdraw existing intents before | ||
432 | - // submitting new intents. | ||
433 | - // | ||
434 | - synchronized (this) { | ||
435 | - MultiPointToSinglePointIntent intent; | ||
436 | - | ||
437 | - log.debug("SDN-IP submitting intents = {} withdrawing = {}", | ||
438 | - updates.size(), withdraws.size()); | ||
439 | - | ||
440 | - // | ||
441 | - // Prepare the Intent batch operations for the intents to withdraw | ||
442 | - // | ||
443 | - for (FibUpdate withdraw : withdraws) { | ||
444 | - checkArgument(withdraw.type() == FibUpdate.Type.DELETE, | ||
445 | - "FibUpdate with wrong type in withdraws list"); | ||
446 | - | ||
447 | - IpPrefix prefix = withdraw.entry().prefix(); | ||
448 | - intent = routeIntents.remove(prefix); | ||
449 | - if (intent == null) { | ||
450 | - log.trace("SDN-IP No intent in routeIntents to delete " + | ||
451 | - "for prefix: {}", prefix); | ||
452 | - continue; | ||
453 | - } | ||
454 | - if (isElectedLeader && isActivatedLeader) { | ||
455 | - log.trace("SDN-IP Withdrawing intent: {}", intent); | ||
456 | - intentService.withdraw(intent); | ||
457 | - } | ||
458 | - } | ||
459 | - | ||
460 | - // | ||
461 | - // Prepare the Intent batch operations for the intents to submit | ||
462 | - // | ||
463 | - for (FibUpdate update : updates) { | ||
464 | - checkArgument(update.type() == FibUpdate.Type.UPDATE, | ||
465 | - "FibUpdate with wrong type in updates list"); | ||
466 | - | ||
467 | - IpPrefix prefix = update.entry().prefix(); | ||
468 | - intent = generateRouteIntent(prefix, update.entry().nextHopIp(), | ||
469 | - update.entry().nextHopMac()); | ||
470 | - | ||
471 | - if (intent == null) { | ||
472 | - // This preserves the old semantics - if an intent can't be | ||
473 | - // generated, we don't do anything with that prefix. But | ||
474 | - // perhaps we should withdraw the old intent anyway? | ||
475 | - continue; | ||
476 | - } | ||
477 | - | ||
478 | - MultiPointToSinglePointIntent oldIntent = | ||
479 | - routeIntents.put(prefix, intent); | ||
480 | - if (isElectedLeader && isActivatedLeader) { | ||
481 | - if (oldIntent != null) { | ||
482 | - log.trace("SDN-IP Withdrawing old intent: {}", | ||
483 | - oldIntent); | ||
484 | - intentService.withdraw(oldIntent); | ||
485 | - } | ||
486 | - log.trace("SDN-IP Submitting intent: {}", intent); | ||
487 | - intentService.submit(intent); | ||
488 | - } | ||
489 | - } | ||
490 | - } | ||
491 | - } | ||
492 | - | ||
493 | - /** | ||
494 | - * Synchronize the in-memory Intents with the Intents in the Intent | ||
495 | - * framework. | ||
496 | - */ | ||
497 | - void synchronizeIntents() { | ||
498 | - synchronized (this) { | ||
499 | - | ||
500 | - Map<IntentKey, Intent> localIntents = new HashMap<>(); | ||
501 | - Map<IntentKey, Intent> fetchedIntents = new HashMap<>(); | ||
502 | - Collection<Intent> storeInMemoryIntents = new LinkedList<>(); | ||
503 | - Collection<Intent> addIntents = new LinkedList<>(); | ||
504 | - Collection<Intent> deleteIntents = new LinkedList<>(); | ||
505 | - | ||
506 | - if (!isElectedLeader) { | ||
507 | - return; // Nothing to do: not the leader anymore | ||
508 | } | 215 | } |
509 | - log.debug("SDN-IP synchronizing all intents..."); | ||
510 | - | ||
511 | - // Prepare the local intents | ||
512 | - for (Intent intent : routeIntents.values()) { | ||
513 | - localIntents.put(new IntentKey(intent), intent); | ||
514 | } | 216 | } |
515 | - for (Intent intent : peerIntents.values()) { | ||
516 | - localIntents.put(new IntentKey(intent), intent); | ||
517 | } | 217 | } |
518 | 218 | ||
519 | - // Fetch all intents for this application | 219 | + for (Intent serviceIntent : serviceIntents.values()) { |
520 | - for (Intent intent : intentService.getIntents()) { | 220 | + IntentState state = intentService.getIntentState(serviceIntent.key()); |
521 | - if (!intent.appId().equals(appId)) { | 221 | + if (state != null && state != IntentState.WITHDRAW_REQ |
522 | - continue; | 222 | + && state != IntentState.WITHDRAWING |
523 | - } | 223 | + && state != IntentState.WITHDRAWN) { |
524 | - fetchedIntents.put(new IntentKey(intent), intent); | 224 | + intentsToRemove.add(serviceIntent); |
525 | - } | ||
526 | - if (log.isDebugEnabled()) { | ||
527 | - for (Intent intent: fetchedIntents.values()) { | ||
528 | - log.trace("SDN-IP Intent Synchronizer: fetched intent: {}", | ||
529 | - intent); | ||
530 | } | 225 | } |
531 | } | 226 | } |
532 | 227 | ||
533 | - computeIntentsDelta(localIntents, fetchedIntents, | 228 | + log.debug("SDN-IP Intent Synchronizer: submitting {}, withdrawing {}", |
534 | - storeInMemoryIntents, addIntents, | 229 | + intentsToAdd.size(), intentsToRemove.size()); |
535 | - deleteIntents); | ||
536 | - | ||
537 | - // | ||
538 | - // Perform the actions: | ||
539 | - // 1. Store in memory fetched intents that are same. Can be done | ||
540 | - // even if we are not the leader anymore | ||
541 | - // 2. Delete intents: check if the leader before the operation | ||
542 | - // 3. Add intents: check if the leader before the operation | ||
543 | - // | ||
544 | - for (Intent intent : storeInMemoryIntents) { | ||
545 | - // Store the intent in memory based on its type | ||
546 | - if (intent instanceof MultiPointToSinglePointIntent) { | ||
547 | - MultiPointToSinglePointIntent mp2pIntent = | ||
548 | - (MultiPointToSinglePointIntent) intent; | ||
549 | - // Find the IP prefix | ||
550 | - Criterion c = | ||
551 | - mp2pIntent.selector().getCriterion(Criterion.Type.IPV4_DST); | ||
552 | - if (c == null) { | ||
553 | - // Try IPv6 | ||
554 | - c = | ||
555 | - mp2pIntent.selector().getCriterion(Criterion.Type.IPV6_DST); | ||
556 | - } | ||
557 | - if (c != null && c instanceof IPCriterion) { | ||
558 | - IPCriterion ipCriterion = (IPCriterion) c; | ||
559 | - IpPrefix ipPrefix = ipCriterion.ip(); | ||
560 | - if (ipPrefix == null) { | ||
561 | - continue; | ||
562 | - } | ||
563 | - log.trace("SDN-IP Intent Synchronizer: updating " + | ||
564 | - "in-memory Route Intent for prefix {}", | ||
565 | - ipPrefix); | ||
566 | - routeIntents.put(ipPrefix, mp2pIntent); | ||
567 | - } else { | ||
568 | - log.warn("SDN-IP no IPV4_DST or IPV6_DST criterion found for Intent {}", | ||
569 | - mp2pIntent.id()); | ||
570 | - } | ||
571 | - continue; | ||
572 | - } | ||
573 | - if (intent instanceof PointToPointIntent) { | ||
574 | - PointToPointIntent p2pIntent = (PointToPointIntent) intent; | ||
575 | - log.trace("SDN-IP Intent Synchronizer: updating " + | ||
576 | - "in-memory Peer Intent {}", p2pIntent); | ||
577 | - peerIntents.put(new IntentKey(intent), p2pIntent); | ||
578 | - continue; | ||
579 | - } | ||
580 | - } | ||
581 | 230 | ||
582 | // Withdraw Intents | 231 | // Withdraw Intents |
583 | - for (Intent intent : deleteIntents) { | 232 | + for (Intent intent : intentsToRemove) { |
584 | intentService.withdraw(intent); | 233 | intentService.withdraw(intent); |
585 | log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}", | 234 | log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}", |
586 | intent); | 235 | intent); |
587 | } | 236 | } |
588 | if (!isElectedLeader) { | 237 | if (!isElectedLeader) { |
589 | - log.trace("SDN-IP Intent Synchronizer: cannot withdraw intents: " + | 238 | + log.debug("SDN-IP Intent Synchronizer: cannot withdraw intents: " + |
590 | "not elected leader anymore"); | 239 | "not elected leader anymore"); |
591 | isActivatedLeader = false; | 240 | isActivatedLeader = false; |
592 | return; | 241 | return; |
593 | } | 242 | } |
594 | 243 | ||
595 | // Add Intents | 244 | // Add Intents |
596 | - for (Intent intent : addIntents) { | 245 | + for (Intent intent : intentsToAdd) { |
597 | intentService.submit(intent); | 246 | intentService.submit(intent); |
598 | log.trace("SDN-IP Intent Synchronizer: submitting intent: {}", | 247 | log.trace("SDN-IP Intent Synchronizer: submitting intent: {}", |
599 | intent); | 248 | intent); |
600 | } | 249 | } |
601 | if (!isElectedLeader) { | 250 | if (!isElectedLeader) { |
602 | - log.trace("SDN-IP Intent Synchronizer: cannot submit intents: " + | 251 | + log.debug("SDN-IP Intent Synchronizer: cannot submit intents: " + |
603 | "not elected leader anymore"); | 252 | "not elected leader anymore"); |
604 | isActivatedLeader = false; | 253 | isActivatedLeader = false; |
605 | return; | 254 | return; |
... | @@ -612,369 +261,5 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { | ... | @@ -612,369 +261,5 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { |
612 | } | 261 | } |
613 | log.debug("SDN-IP intent synchronization completed"); | 262 | log.debug("SDN-IP intent synchronization completed"); |
614 | } | 263 | } |
615 | - } | ||
616 | - | ||
617 | - /** | ||
618 | - * Computes the delta in two sets of Intents: local in-memory Intents, | ||
619 | - * and intents fetched from the Intent framework. | ||
620 | - * | ||
621 | - * @param localIntents the local in-memory Intents | ||
622 | - * @param fetchedIntents the Intents fetched from the Intent framework | ||
623 | - * @param storeInMemoryIntents the Intents that should be stored in memory. | ||
624 | - * Note: This Collection must be allocated by the caller, and it will | ||
625 | - * be populated by this method. | ||
626 | - * @param addIntents the Intents that should be added to the Intent | ||
627 | - * framework. Note: This Collection must be allocated by the caller, and | ||
628 | - * it will be populated by this method. | ||
629 | - * @param deleteIntents the Intents that should be deleted from the Intent | ||
630 | - * framework. Note: This Collection must be allocated by the caller, and | ||
631 | - * it will be populated by this method. | ||
632 | - */ | ||
633 | - private void computeIntentsDelta( | ||
634 | - final Map<IntentKey, Intent> localIntents, | ||
635 | - final Map<IntentKey, Intent> fetchedIntents, | ||
636 | - Collection<Intent> storeInMemoryIntents, | ||
637 | - Collection<Intent> addIntents, | ||
638 | - Collection<Intent> deleteIntents) { | ||
639 | - | ||
640 | - // | ||
641 | - // Compute the deltas between the LOCAL in-memory Intents and the | ||
642 | - // FETCHED Intents: | ||
643 | - // - If an Intent is in both the LOCAL and FETCHED sets: | ||
644 | - // If the FETCHED Intent is WITHDRAWING or WITHDRAWN, then | ||
645 | - // the LOCAL Intent should be added/installed; otherwise the | ||
646 | - // FETCHED intent should be stored in the local memory | ||
647 | - // (i.e., override the LOCAL Intent) to preserve the original | ||
648 | - // Intent ID. | ||
649 | - // - if a LOCAL Intent is not in the FETCHED set, then the LOCAL | ||
650 | - // Intent should be added/installed. | ||
651 | - // - If a FETCHED Intent is not in the LOCAL set, then the FETCHED | ||
652 | - // Intent should be deleted/withdrawn. | ||
653 | - // | ||
654 | - for (Map.Entry<IntentKey, Intent> entry : localIntents.entrySet()) { | ||
655 | - IntentKey intentKey = entry.getKey(); | ||
656 | - Intent localIntent = entry.getValue(); | ||
657 | - Intent fetchedIntent = fetchedIntents.get(intentKey); | ||
658 | - | ||
659 | - if (fetchedIntent == null) { | ||
660 | - // | ||
661 | - // No FETCHED Intent found: push the LOCAL Intent. | ||
662 | - // | ||
663 | - addIntents.add(localIntent); | ||
664 | - continue; | ||
665 | - } | ||
666 | - | ||
667 | - IntentState state = | ||
668 | - intentService.getIntentState(fetchedIntent.key()); | ||
669 | - if (state == null || | ||
670 | - state == IntentState.WITHDRAWING || | ||
671 | - state == IntentState.WITHDRAWN) { | ||
672 | - // The intent has been withdrawn but according to our route | ||
673 | - // table it should be installed. We'll reinstall it. | ||
674 | - addIntents.add(localIntent); | ||
675 | - continue; | ||
676 | - } | ||
677 | - storeInMemoryIntents.add(fetchedIntent); | ||
678 | - } | ||
679 | - | ||
680 | - for (Map.Entry<IntentKey, Intent> entry : fetchedIntents.entrySet()) { | ||
681 | - IntentKey intentKey = entry.getKey(); | ||
682 | - Intent fetchedIntent = entry.getValue(); | ||
683 | - Intent localIntent = localIntents.get(intentKey); | ||
684 | - | ||
685 | - if (localIntent != null) { | ||
686 | - continue; | ||
687 | - } | ||
688 | - | ||
689 | - IntentState state = | ||
690 | - intentService.getIntentState(fetchedIntent.key()); | ||
691 | - if (state == null || | ||
692 | - state == IntentState.WITHDRAWING || | ||
693 | - state == IntentState.WITHDRAWN) { | ||
694 | - // Nothing to do. The intent has been already withdrawn. | ||
695 | - continue; | ||
696 | - } | ||
697 | - // | ||
698 | - // No LOCAL Intent found: delete/withdraw the FETCHED Intent. | ||
699 | - // | ||
700 | - deleteIntents.add(fetchedIntent); | ||
701 | - } | ||
702 | - } | ||
703 | - | ||
704 | - /** | ||
705 | - * Helper class that can be used to compute the key for an Intent by | ||
706 | - * by excluding the Intent ID. | ||
707 | - */ | ||
708 | - static final class IntentKey { | ||
709 | - private final Intent intent; | ||
710 | - | ||
711 | - /** | ||
712 | - * Constructor. | ||
713 | - * | ||
714 | - * @param intent the intent to use | ||
715 | - */ | ||
716 | - IntentKey(Intent intent) { | ||
717 | - checkArgument((intent instanceof MultiPointToSinglePointIntent) || | ||
718 | - (intent instanceof PointToPointIntent), | ||
719 | - "Intent type not recognized", intent); | ||
720 | - this.intent = intent; | ||
721 | - } | ||
722 | 264 | ||
723 | - /** | ||
724 | - * Compares two Multi-Point to Single-Point Intents whether they | ||
725 | - * represent same logical intention. | ||
726 | - * | ||
727 | - * @param intent1 the first Intent to compare | ||
728 | - * @param intent2 the second Intent to compare | ||
729 | - * @return true if both Intents represent same logical intention, | ||
730 | - * otherwise false | ||
731 | - */ | ||
732 | - static boolean equalIntents(MultiPointToSinglePointIntent intent1, | ||
733 | - MultiPointToSinglePointIntent intent2) { | ||
734 | - return Objects.equals(intent1.appId(), intent2.appId()) && | ||
735 | - Objects.equals(intent1.selector(), intent2.selector()) && | ||
736 | - Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
737 | - Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) && | ||
738 | - Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
739 | - } | ||
740 | - | ||
741 | - /** | ||
742 | - * Compares two Point-to-Point Intents whether they represent | ||
743 | - * same logical intention. | ||
744 | - * | ||
745 | - * @param intent1 the first Intent to compare | ||
746 | - * @param intent2 the second Intent to compare | ||
747 | - * @return true if both Intents represent same logical intention, | ||
748 | - * otherwise false | ||
749 | - */ | ||
750 | - static boolean equalIntents(PointToPointIntent intent1, | ||
751 | - PointToPointIntent intent2) { | ||
752 | - return Objects.equals(intent1.appId(), intent2.appId()) && | ||
753 | - Objects.equals(intent1.selector(), intent2.selector()) && | ||
754 | - Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
755 | - Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) && | ||
756 | - Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
757 | - } | ||
758 | - | ||
759 | - @Override | ||
760 | - public int hashCode() { | ||
761 | - if (intent instanceof PointToPointIntent) { | ||
762 | - PointToPointIntent p2pIntent = (PointToPointIntent) intent; | ||
763 | - return Objects.hash(p2pIntent.appId(), | ||
764 | - p2pIntent.resources(), | ||
765 | - p2pIntent.selector(), | ||
766 | - p2pIntent.treatment(), | ||
767 | - p2pIntent.constraints(), | ||
768 | - p2pIntent.ingressPoint(), | ||
769 | - p2pIntent.egressPoint()); | ||
770 | - } | ||
771 | - if (intent instanceof MultiPointToSinglePointIntent) { | ||
772 | - MultiPointToSinglePointIntent m2pIntent = | ||
773 | - (MultiPointToSinglePointIntent) intent; | ||
774 | - return Objects.hash(m2pIntent.appId(), | ||
775 | - m2pIntent.resources(), | ||
776 | - m2pIntent.selector(), | ||
777 | - m2pIntent.treatment(), | ||
778 | - m2pIntent.constraints(), | ||
779 | - m2pIntent.ingressPoints(), | ||
780 | - m2pIntent.egressPoint()); | ||
781 | - } | ||
782 | - checkArgument(false, "Intent type not recognized", intent); | ||
783 | - return 0; | ||
784 | - } | ||
785 | - | ||
786 | - @Override | ||
787 | - public boolean equals(Object obj) { | ||
788 | - if (this == obj) { | ||
789 | - return true; | ||
790 | - } | ||
791 | - if ((obj == null) || (!(obj instanceof IntentKey))) { | ||
792 | - return false; | ||
793 | - } | ||
794 | - IntentKey other = (IntentKey) obj; | ||
795 | - | ||
796 | - if (this.intent instanceof PointToPointIntent) { | ||
797 | - if (!(other.intent instanceof PointToPointIntent)) { | ||
798 | - return false; | ||
799 | - } | ||
800 | - return equalIntents((PointToPointIntent) this.intent, | ||
801 | - (PointToPointIntent) other.intent); | ||
802 | - } | ||
803 | - if (this.intent instanceof MultiPointToSinglePointIntent) { | ||
804 | - if (!(other.intent instanceof MultiPointToSinglePointIntent)) { | ||
805 | - return false; | ||
806 | - } | ||
807 | - return equalIntents( | ||
808 | - (MultiPointToSinglePointIntent) this.intent, | ||
809 | - (MultiPointToSinglePointIntent) other.intent); | ||
810 | - } | ||
811 | - checkArgument(false, "Intent type not recognized", intent); | ||
812 | - return false; | ||
813 | - } | ||
814 | - } | ||
815 | - | ||
816 | - @Override | ||
817 | - public void setUpConnectivityHostToHost(IpAddress dstIpAddress, | ||
818 | - IpAddress srcIpAddress, | ||
819 | - MacAddress srcMacAddress, | ||
820 | - ConnectPoint srcConnectPoint) { | ||
821 | - checkNotNull(dstIpAddress); | ||
822 | - checkNotNull(srcIpAddress); | ||
823 | - checkNotNull(srcMacAddress); | ||
824 | - checkNotNull(srcConnectPoint); | ||
825 | - | ||
826 | - IpPrefix srcIpPrefix = srcIpAddress.toIpPrefix(); | ||
827 | - IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix(); | ||
828 | - ConnectPoint dstConnectPoint = null; | ||
829 | - MacAddress dstMacAddress = null; | ||
830 | - | ||
831 | - for (Host host : hostService.getHostsByIp(dstIpAddress)) { | ||
832 | - if (host.mac() != null) { | ||
833 | - dstMacAddress = host.mac(); | ||
834 | - dstConnectPoint = host.location(); | ||
835 | - break; | ||
836 | - } | ||
837 | - } | ||
838 | - if (dstMacAddress == null) { | ||
839 | - hostService.startMonitoringIp(dstIpAddress); | ||
840 | - return; | ||
841 | - } | ||
842 | - | ||
843 | - // | ||
844 | - // Handle intent from source host to destination host | ||
845 | - // | ||
846 | - MultiPointToSinglePointIntent srcToDstIntent = | ||
847 | - hostToHostIntentGenerator(dstIpAddress, dstConnectPoint, | ||
848 | - dstMacAddress, srcConnectPoint); | ||
849 | - submitReactiveIntent(dstIpPrefix, srcToDstIntent); | ||
850 | - | ||
851 | - // | ||
852 | - // Handle intent from destination host to source host | ||
853 | - // | ||
854 | - | ||
855 | - // Since we proactively handle the intent from destination host to | ||
856 | - // source host, we should check whether there is an exiting intent | ||
857 | - // first. | ||
858 | - if (mp2pIntentExists(srcIpPrefix)) { | ||
859 | - updateExistingMp2pIntent(srcIpPrefix, dstConnectPoint); | ||
860 | - return; | ||
861 | - } else { | ||
862 | - // There is no existing intent, create a new one. | ||
863 | - MultiPointToSinglePointIntent dstToSrcIntent = | ||
864 | - hostToHostIntentGenerator(srcIpAddress, srcConnectPoint, | ||
865 | - srcMacAddress, dstConnectPoint); | ||
866 | - submitReactiveIntent(srcIpPrefix, dstToSrcIntent); | ||
867 | - } | ||
868 | - } | ||
869 | - | ||
870 | - /** | ||
871 | - * Generates MultiPointToSinglePointIntent for both source host and | ||
872 | - * destination host located in local SDN network. | ||
873 | - * | ||
874 | - * @param dstIpAddress the destination IP address | ||
875 | - * @param dstConnectPoint the destination host connect point | ||
876 | - * @param dstMacAddress the MAC address of destination host | ||
877 | - * @param srcConnectPoint the connect point where packet-in from | ||
878 | - * @return the generated MultiPointToSinglePointIntent | ||
879 | - */ | ||
880 | - private MultiPointToSinglePointIntent hostToHostIntentGenerator( | ||
881 | - IpAddress dstIpAddress, | ||
882 | - ConnectPoint dstConnectPoint, | ||
883 | - MacAddress dstMacAddress, | ||
884 | - ConnectPoint srcConnectPoint) { | ||
885 | - checkNotNull(dstIpAddress); | ||
886 | - checkNotNull(dstConnectPoint); | ||
887 | - checkNotNull(dstMacAddress); | ||
888 | - checkNotNull(srcConnectPoint); | ||
889 | - | ||
890 | - Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
891 | - ingressPoints.add(srcConnectPoint); | ||
892 | - IpPrefix dstIpPrefix = dstIpAddress.toIpPrefix(); | ||
893 | - | ||
894 | - TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
895 | - if (dstIpAddress.isIp4()) { | ||
896 | - selector.matchEthType(Ethernet.TYPE_IPV4); | ||
897 | - selector.matchIPDst(dstIpPrefix); | ||
898 | - } else { | ||
899 | - selector.matchEthType(Ethernet.TYPE_IPV6); | ||
900 | - selector.matchIPv6Dst(dstIpPrefix); | ||
901 | - } | ||
902 | - | ||
903 | - // Rewrite the destination MAC address | ||
904 | - TrafficTreatment.Builder treatment = | ||
905 | - DefaultTrafficTreatment.builder().setEthDst(dstMacAddress); | ||
906 | - | ||
907 | - Key key = Key.of(dstIpPrefix.toString(), appId); | ||
908 | - int priority = dstIpPrefix.prefixLength() * PRIORITY_MULTIPLIER | ||
909 | - + PRIORITY_OFFSET; | ||
910 | - MultiPointToSinglePointIntent intent = | ||
911 | - MultiPointToSinglePointIntent.builder() | ||
912 | - .appId(appId) | ||
913 | - .key(key) | ||
914 | - .selector(selector.build()) | ||
915 | - .treatment(treatment.build()) | ||
916 | - .ingressPoints(ingressPoints) | ||
917 | - .egressPoint(dstConnectPoint) | ||
918 | - .priority(priority) | ||
919 | - .constraints(CONSTRAINTS) | ||
920 | - .build(); | ||
921 | - | ||
922 | - log.trace("Generates ConnectivityHostToHost = {} ", intent); | ||
923 | - return intent; | ||
924 | - } | ||
925 | - | ||
926 | - @Override | ||
927 | - public void updateExistingMp2pIntent(IpPrefix ipPrefix, | ||
928 | - ConnectPoint ingressConnectPoint) { | ||
929 | - checkNotNull(ipPrefix); | ||
930 | - checkNotNull(ingressConnectPoint); | ||
931 | - | ||
932 | - MultiPointToSinglePointIntent existingIntent = | ||
933 | - getExistingMp2pIntent(ipPrefix); | ||
934 | - if (existingIntent != null) { | ||
935 | - Set<ConnectPoint> ingressPoints = existingIntent.ingressPoints(); | ||
936 | - // Add host connect point into ingressPoints of the existing intent | ||
937 | - if (ingressPoints.add(ingressConnectPoint)) { | ||
938 | - MultiPointToSinglePointIntent updatedMp2pIntent = | ||
939 | - MultiPointToSinglePointIntent.builder() | ||
940 | - .appId(appId) | ||
941 | - .key(existingIntent.key()) | ||
942 | - .selector(existingIntent.selector()) | ||
943 | - .treatment(existingIntent.treatment()) | ||
944 | - .ingressPoints(ingressPoints) | ||
945 | - .egressPoint(existingIntent.egressPoint()) | ||
946 | - .priority(existingIntent.priority()) | ||
947 | - .constraints(CONSTRAINTS) | ||
948 | - .build(); | ||
949 | - | ||
950 | - log.trace("Update an existing MultiPointToSinglePointIntent " | ||
951 | - + "to new intent = {} ", updatedMp2pIntent); | ||
952 | - submitReactiveIntent(ipPrefix, updatedMp2pIntent); | ||
953 | - } | ||
954 | - // If adding ingressConnectPoint to ingressPoints failed, it | ||
955 | - // because between the time interval from checking existing intent | ||
956 | - // to generating new intent, onos updated this intent due to other | ||
957 | - // packet-in and the new intent also includes the | ||
958 | - // ingressConnectPoint. This will not affect reactive routing. | ||
959 | - } | ||
960 | - } | ||
961 | - | ||
962 | - @Override | ||
963 | - public boolean mp2pIntentExists(IpPrefix ipPrefix) { | ||
964 | - checkNotNull(ipPrefix); | ||
965 | - return routeIntents.get(ipPrefix) != null; | ||
966 | - } | ||
967 | - | ||
968 | - /** | ||
969 | - * Gets the existing MultiPointToSinglePointIntent from memory for a given | ||
970 | - * IP prefix. | ||
971 | - * | ||
972 | - * @param ipPrefix the IP prefix used to find MultiPointToSinglePointIntent | ||
973 | - * @return the MultiPointToSinglePointIntent if found, otherwise null | ||
974 | - */ | ||
975 | - private MultiPointToSinglePointIntent getExistingMp2pIntent(IpPrefix | ||
976 | - ipPrefix) { | ||
977 | - checkNotNull(ipPrefix); | ||
978 | - return routeIntents.get(ipPrefix); | ||
979 | - } | ||
980 | } | 265 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.sdnip; | ||
18 | + | ||
19 | +import org.onosproject.net.intent.Intent; | ||
20 | +import org.onosproject.net.intent.MultiPointToSinglePointIntent; | ||
21 | +import org.onosproject.net.intent.PointToPointIntent; | ||
22 | +import org.slf4j.Logger; | ||
23 | +import org.slf4j.LoggerFactory; | ||
24 | + | ||
25 | +import java.util.Objects; | ||
26 | + | ||
27 | +import static com.google.common.base.Preconditions.checkArgument; | ||
28 | + | ||
29 | +/** | ||
30 | + * Utilities for dealing with intents. | ||
31 | + */ | ||
32 | +public final class IntentUtils { | ||
33 | + | ||
34 | + private static final Logger log = LoggerFactory.getLogger(IntentUtils.class); | ||
35 | + | ||
36 | + private IntentUtils() { | ||
37 | + | ||
38 | + } | ||
39 | + | ||
40 | + /** | ||
41 | + * Checks if two intents represent the same value. | ||
42 | + * | ||
43 | + * <p>({@link Intent#equals(Object)} only checks ID equality)</p> | ||
44 | + * | ||
45 | + * <p>Both intents must be of the same type.</p> | ||
46 | + * | ||
47 | + * @param one first intent | ||
48 | + * @param two second intent | ||
49 | + * @return true if the two intents represent the same value, otherwise false | ||
50 | + */ | ||
51 | + public static boolean equals(Intent one, Intent two) { | ||
52 | + checkArgument(one.getClass() == two.getClass(), | ||
53 | + "Intents are not the same type"); | ||
54 | + | ||
55 | + if (!(Objects.equals(one.appId(), two.appId()) && | ||
56 | + Objects.equals(one.key(), two.key()))) { | ||
57 | + return false; | ||
58 | + } | ||
59 | + | ||
60 | + if (one instanceof MultiPointToSinglePointIntent) { | ||
61 | + MultiPointToSinglePointIntent intent1 = (MultiPointToSinglePointIntent) one; | ||
62 | + MultiPointToSinglePointIntent intent2 = (MultiPointToSinglePointIntent) two; | ||
63 | + | ||
64 | + return Objects.equals(intent1.selector(), intent2.selector()) && | ||
65 | + Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
66 | + Objects.equals(intent1.ingressPoints(), intent2.ingressPoints()) && | ||
67 | + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
68 | + } else if (one instanceof PointToPointIntent) { | ||
69 | + PointToPointIntent intent1 = (PointToPointIntent) one; | ||
70 | + PointToPointIntent intent2 = (PointToPointIntent) two; | ||
71 | + | ||
72 | + return Objects.equals(intent1.selector(), intent2.selector()) && | ||
73 | + Objects.equals(intent1.treatment(), intent2.treatment()) && | ||
74 | + Objects.equals(intent1.ingressPoint(), intent2.ingressPoint()) && | ||
75 | + Objects.equals(intent1.egressPoint(), intent2.egressPoint()); | ||
76 | + } else { | ||
77 | + log.error("Unimplemented intent type"); | ||
78 | + return false; | ||
79 | + } | ||
80 | + } | ||
81 | +} |
... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.sdnip; | 16 | package org.onosproject.sdnip; |
17 | 17 | ||
18 | +import com.google.common.collect.HashMultimap; | ||
19 | +import com.google.common.collect.Multimap; | ||
18 | import org.onlab.packet.Ethernet; | 20 | import org.onlab.packet.Ethernet; |
19 | import org.onlab.packet.IPv4; | 21 | import org.onlab.packet.IPv4; |
20 | import org.onlab.packet.IPv6; | 22 | import org.onlab.packet.IPv6; |
... | @@ -22,16 +24,18 @@ import org.onlab.packet.IpAddress; | ... | @@ -22,16 +24,18 @@ import org.onlab.packet.IpAddress; |
22 | import org.onlab.packet.IpPrefix; | 24 | import org.onlab.packet.IpPrefix; |
23 | import org.onlab.packet.TpPort; | 25 | import org.onlab.packet.TpPort; |
24 | import org.onosproject.core.ApplicationId; | 26 | import org.onosproject.core.ApplicationId; |
25 | -import org.onosproject.net.config.NetworkConfigService; | ||
26 | import org.onosproject.incubator.net.intf.Interface; | 27 | import org.onosproject.incubator.net.intf.Interface; |
27 | import org.onosproject.incubator.net.intf.InterfaceService; | 28 | import org.onosproject.incubator.net.intf.InterfaceService; |
28 | import org.onosproject.net.ConnectPoint; | 29 | import org.onosproject.net.ConnectPoint; |
30 | +import org.onosproject.net.config.NetworkConfigService; | ||
29 | import org.onosproject.net.flow.DefaultTrafficSelector; | 31 | import org.onosproject.net.flow.DefaultTrafficSelector; |
30 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 32 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
31 | import org.onosproject.net.flow.TrafficSelector; | 33 | import org.onosproject.net.flow.TrafficSelector; |
32 | import org.onosproject.net.flow.TrafficTreatment; | 34 | import org.onosproject.net.flow.TrafficTreatment; |
33 | import org.onosproject.net.host.InterfaceIpAddress; | 35 | import org.onosproject.net.host.InterfaceIpAddress; |
36 | +import org.onosproject.net.intent.Key; | ||
34 | import org.onosproject.net.intent.PointToPointIntent; | 37 | import org.onosproject.net.intent.PointToPointIntent; |
38 | +import org.onosproject.routing.IntentSynchronizationService; | ||
35 | import org.onosproject.routing.RoutingService; | 39 | import org.onosproject.routing.RoutingService; |
36 | import org.onosproject.routing.config.BgpConfig; | 40 | import org.onosproject.routing.config.BgpConfig; |
37 | import org.slf4j.Logger; | 41 | import org.slf4j.Logger; |
... | @@ -49,18 +53,26 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -49,18 +53,26 @@ import static com.google.common.base.Preconditions.checkNotNull; |
49 | public class PeerConnectivityManager { | 53 | public class PeerConnectivityManager { |
50 | private static final int PRIORITY_OFFSET = 1000; | 54 | private static final int PRIORITY_OFFSET = 1000; |
51 | 55 | ||
56 | + private static final String SUFFIX_DST = "dst"; | ||
57 | + private static final String SUFFIX_SRC = "src"; | ||
58 | + private static final String SUFFIX_ICMP = "icmp"; | ||
59 | + | ||
52 | private static final Logger log = LoggerFactory.getLogger( | 60 | private static final Logger log = LoggerFactory.getLogger( |
53 | PeerConnectivityManager.class); | 61 | PeerConnectivityManager.class); |
54 | 62 | ||
55 | private static final short BGP_PORT = 179; | 63 | private static final short BGP_PORT = 179; |
56 | 64 | ||
57 | - private final IntentSynchronizer intentSynchronizer; | 65 | + private final IntentSynchronizationService intentSynchronizer; |
58 | private final NetworkConfigService configService; | 66 | private final NetworkConfigService configService; |
59 | private final InterfaceService interfaceService; | 67 | private final InterfaceService interfaceService; |
60 | 68 | ||
61 | private final ApplicationId appId; | 69 | private final ApplicationId appId; |
62 | private final ApplicationId routerAppId; | 70 | private final ApplicationId routerAppId; |
63 | 71 | ||
72 | + // Just putting something random here for now. Figure out exactly what | ||
73 | + // indexes we need when we start making use of them. | ||
74 | + private final Multimap<BgpConfig.BgpSpeakerConfig, PointToPointIntent> peerIntents; | ||
75 | + | ||
64 | /** | 76 | /** |
65 | * Creates a new PeerConnectivityManager. | 77 | * Creates a new PeerConnectivityManager. |
66 | * | 78 | * |
... | @@ -71,7 +83,7 @@ public class PeerConnectivityManager { | ... | @@ -71,7 +83,7 @@ public class PeerConnectivityManager { |
71 | * @param routerAppId application ID | 83 | * @param routerAppId application ID |
72 | */ | 84 | */ |
73 | public PeerConnectivityManager(ApplicationId appId, | 85 | public PeerConnectivityManager(ApplicationId appId, |
74 | - IntentSynchronizer intentSynchronizer, | 86 | + IntentSynchronizationService intentSynchronizer, |
75 | NetworkConfigService configService, | 87 | NetworkConfigService configService, |
76 | ApplicationId routerAppId, | 88 | ApplicationId routerAppId, |
77 | InterfaceService interfaceService) { | 89 | InterfaceService interfaceService) { |
... | @@ -80,6 +92,8 @@ public class PeerConnectivityManager { | ... | @@ -80,6 +92,8 @@ public class PeerConnectivityManager { |
80 | this.configService = configService; | 92 | this.configService = configService; |
81 | this.routerAppId = routerAppId; | 93 | this.routerAppId = routerAppId; |
82 | this.interfaceService = interfaceService; | 94 | this.interfaceService = interfaceService; |
95 | + | ||
96 | + peerIntents = HashMultimap.create(); | ||
83 | } | 97 | } |
84 | 98 | ||
85 | /** | 99 | /** |
... | @@ -100,8 +114,6 @@ public class PeerConnectivityManager { | ... | @@ -100,8 +114,6 @@ public class PeerConnectivityManager { |
100 | * BGP speakers and external BGP peers. | 114 | * BGP speakers and external BGP peers. |
101 | */ | 115 | */ |
102 | private void setUpConnectivity() { | 116 | private void setUpConnectivity() { |
103 | - List<PointToPointIntent> intents = new ArrayList<>(); | ||
104 | - | ||
105 | BgpConfig config = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS); | 117 | BgpConfig config = configService.getConfig(routerAppId, RoutingService.CONFIG_CLASS); |
106 | 118 | ||
107 | if (config == null) { | 119 | if (config == null) { |
... | @@ -113,11 +125,12 @@ public class PeerConnectivityManager { | ... | @@ -113,11 +125,12 @@ public class PeerConnectivityManager { |
113 | log.debug("Start to set up BGP paths for BGP speaker: {}", | 125 | log.debug("Start to set up BGP paths for BGP speaker: {}", |
114 | bgpSpeaker); | 126 | bgpSpeaker); |
115 | 127 | ||
116 | - intents.addAll(buildSpeakerIntents(bgpSpeaker)); | 128 | + buildSpeakerIntents(bgpSpeaker).forEach(i -> { |
117 | - } | 129 | + peerIntents.put(bgpSpeaker, i); |
130 | + intentSynchronizer.submit(i); | ||
131 | + }); | ||
118 | 132 | ||
119 | - // Submit all the intents. | 133 | + } |
120 | - intentSynchronizer.submitPeerIntents(intents); | ||
121 | } | 134 | } |
122 | 135 | ||
123 | private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) { | 136 | private Collection<PointToPointIntent> buildSpeakerIntents(BgpConfig.BgpSpeakerConfig speaker) { |
... | @@ -167,8 +180,8 @@ public class PeerConnectivityManager { | ... | @@ -167,8 +180,8 @@ public class PeerConnectivityManager { |
167 | List<PointToPointIntent> intents = new ArrayList<>(); | 180 | List<PointToPointIntent> intents = new ArrayList<>(); |
168 | 181 | ||
169 | TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); | 182 | TrafficTreatment treatment = DefaultTrafficTreatment.emptyTreatment(); |
170 | - | ||
171 | TrafficSelector selector; | 183 | TrafficSelector selector; |
184 | + Key key; | ||
172 | 185 | ||
173 | byte tcpProtocol; | 186 | byte tcpProtocol; |
174 | byte icmpProtocol; | 187 | byte icmpProtocol; |
... | @@ -188,8 +201,11 @@ public class PeerConnectivityManager { | ... | @@ -188,8 +201,11 @@ public class PeerConnectivityManager { |
188 | null, | 201 | null, |
189 | BGP_PORT); | 202 | BGP_PORT); |
190 | 203 | ||
204 | + key = buildKey(ipOne, ipTwo, SUFFIX_DST); | ||
205 | + | ||
191 | intents.add(PointToPointIntent.builder() | 206 | intents.add(PointToPointIntent.builder() |
192 | .appId(appId) | 207 | .appId(appId) |
208 | + .key(key) | ||
193 | .selector(selector) | 209 | .selector(selector) |
194 | .treatment(treatment) | 210 | .treatment(treatment) |
195 | .ingressPoint(portOne) | 211 | .ingressPoint(portOne) |
... | @@ -204,8 +220,11 @@ public class PeerConnectivityManager { | ... | @@ -204,8 +220,11 @@ public class PeerConnectivityManager { |
204 | BGP_PORT, | 220 | BGP_PORT, |
205 | null); | 221 | null); |
206 | 222 | ||
223 | + key = buildKey(ipOne, ipTwo, SUFFIX_SRC); | ||
224 | + | ||
207 | intents.add(PointToPointIntent.builder() | 225 | intents.add(PointToPointIntent.builder() |
208 | .appId(appId) | 226 | .appId(appId) |
227 | + .key(key) | ||
209 | .selector(selector) | 228 | .selector(selector) |
210 | .treatment(treatment) | 229 | .treatment(treatment) |
211 | .ingressPoint(portOne) | 230 | .ingressPoint(portOne) |
... | @@ -220,8 +239,11 @@ public class PeerConnectivityManager { | ... | @@ -220,8 +239,11 @@ public class PeerConnectivityManager { |
220 | null, | 239 | null, |
221 | BGP_PORT); | 240 | BGP_PORT); |
222 | 241 | ||
242 | + key = buildKey(ipTwo, ipOne, SUFFIX_DST); | ||
243 | + | ||
223 | intents.add(PointToPointIntent.builder() | 244 | intents.add(PointToPointIntent.builder() |
224 | .appId(appId) | 245 | .appId(appId) |
246 | + .key(key) | ||
225 | .selector(selector) | 247 | .selector(selector) |
226 | .treatment(treatment) | 248 | .treatment(treatment) |
227 | .ingressPoint(portTwo) | 249 | .ingressPoint(portTwo) |
... | @@ -236,8 +258,11 @@ public class PeerConnectivityManager { | ... | @@ -236,8 +258,11 @@ public class PeerConnectivityManager { |
236 | BGP_PORT, | 258 | BGP_PORT, |
237 | null); | 259 | null); |
238 | 260 | ||
261 | + key = buildKey(ipTwo, ipOne, SUFFIX_SRC); | ||
262 | + | ||
239 | intents.add(PointToPointIntent.builder() | 263 | intents.add(PointToPointIntent.builder() |
240 | .appId(appId) | 264 | .appId(appId) |
265 | + .key(key) | ||
241 | .selector(selector) | 266 | .selector(selector) |
242 | .treatment(treatment) | 267 | .treatment(treatment) |
243 | .ingressPoint(portTwo) | 268 | .ingressPoint(portTwo) |
... | @@ -252,8 +277,11 @@ public class PeerConnectivityManager { | ... | @@ -252,8 +277,11 @@ public class PeerConnectivityManager { |
252 | null, | 277 | null, |
253 | null); | 278 | null); |
254 | 279 | ||
280 | + key = buildKey(ipOne, ipTwo, SUFFIX_ICMP); | ||
281 | + | ||
255 | intents.add(PointToPointIntent.builder() | 282 | intents.add(PointToPointIntent.builder() |
256 | .appId(appId) | 283 | .appId(appId) |
284 | + .key(key) | ||
257 | .selector(selector) | 285 | .selector(selector) |
258 | .treatment(treatment) | 286 | .treatment(treatment) |
259 | .ingressPoint(portOne) | 287 | .ingressPoint(portOne) |
... | @@ -268,8 +296,11 @@ public class PeerConnectivityManager { | ... | @@ -268,8 +296,11 @@ public class PeerConnectivityManager { |
268 | null, | 296 | null, |
269 | null); | 297 | null); |
270 | 298 | ||
299 | + key = buildKey(ipTwo, ipOne, SUFFIX_ICMP); | ||
300 | + | ||
271 | intents.add(PointToPointIntent.builder() | 301 | intents.add(PointToPointIntent.builder() |
272 | .appId(appId) | 302 | .appId(appId) |
303 | + .key(key) | ||
273 | .selector(selector) | 304 | .selector(selector) |
274 | .treatment(treatment) | 305 | .treatment(treatment) |
275 | .ingressPoint(portTwo) | 306 | .ingressPoint(portTwo) |
... | @@ -316,4 +347,27 @@ public class PeerConnectivityManager { | ... | @@ -316,4 +347,27 @@ public class PeerConnectivityManager { |
316 | return builder.build(); | 347 | return builder.build(); |
317 | } | 348 | } |
318 | 349 | ||
350 | + /** | ||
351 | + * Builds an intent Key for a point-to-point intent based off the source | ||
352 | + * and destination IP address, as well as a suffix String to distinguish | ||
353 | + * between different types of intents between the same source and | ||
354 | + * destination. | ||
355 | + * | ||
356 | + * @param srcIp source IP address | ||
357 | + * @param dstIp destination IP address | ||
358 | + * @param suffix suffix string | ||
359 | + * @return | ||
360 | + */ | ||
361 | + private Key buildKey(IpAddress srcIp, IpAddress dstIp, String suffix) { | ||
362 | + String keyString = new StringBuilder() | ||
363 | + .append(srcIp.toString()) | ||
364 | + .append("-") | ||
365 | + .append(dstIp.toString()) | ||
366 | + .append("-") | ||
367 | + .append(suffix) | ||
368 | + .toString(); | ||
369 | + | ||
370 | + return Key.of(keyString, appId); | ||
371 | + } | ||
372 | + | ||
319 | } | 373 | } | ... | ... |
... | @@ -32,7 +32,9 @@ import org.onosproject.net.config.NetworkConfigService; | ... | @@ -32,7 +32,9 @@ import org.onosproject.net.config.NetworkConfigService; |
32 | import org.onosproject.incubator.net.intf.InterfaceService; | 32 | import org.onosproject.incubator.net.intf.InterfaceService; |
33 | import org.onosproject.net.host.HostService; | 33 | import org.onosproject.net.host.HostService; |
34 | import org.onosproject.net.intent.IntentService; | 34 | import org.onosproject.net.intent.IntentService; |
35 | +import org.onosproject.routing.IntentSynchronizationService; | ||
35 | import org.onosproject.routing.RoutingService; | 36 | import org.onosproject.routing.RoutingService; |
37 | +import org.onosproject.routing.SdnIpService; | ||
36 | import org.onosproject.routing.config.RoutingConfigurationService; | 38 | import org.onosproject.routing.config.RoutingConfigurationService; |
37 | import org.slf4j.Logger; | 39 | import org.slf4j.Logger; |
38 | 40 | ||
... | @@ -79,6 +81,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -79,6 +81,7 @@ public class SdnIp implements SdnIpService { |
79 | 81 | ||
80 | private IntentSynchronizer intentSynchronizer; | 82 | private IntentSynchronizer intentSynchronizer; |
81 | private PeerConnectivityManager peerConnectivity; | 83 | private PeerConnectivityManager peerConnectivity; |
84 | + private SdnIpFib fib; | ||
82 | 85 | ||
83 | private LeadershipEventListener leadershipEventListener = | 86 | private LeadershipEventListener leadershipEventListener = |
84 | new InnerLeadershipEventListener(); | 87 | new InnerLeadershipEventListener(); |
... | @@ -93,10 +96,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -93,10 +96,7 @@ public class SdnIp implements SdnIpService { |
93 | 96 | ||
94 | localControllerNode = clusterService.getLocalNode(); | 97 | localControllerNode = clusterService.getLocalNode(); |
95 | 98 | ||
96 | - intentSynchronizer = new IntentSynchronizer(appId, intentService, | 99 | + intentSynchronizer = new IntentSynchronizer(appId, intentService); |
97 | - hostService, | ||
98 | - config, | ||
99 | - interfaceService); | ||
100 | intentSynchronizer.start(); | 100 | intentSynchronizer.start(); |
101 | 101 | ||
102 | peerConnectivity = new PeerConnectivityManager(appId, | 102 | peerConnectivity = new PeerConnectivityManager(appId, |
... | @@ -106,8 +106,9 @@ public class SdnIp implements SdnIpService { | ... | @@ -106,8 +106,9 @@ public class SdnIp implements SdnIpService { |
106 | interfaceService); | 106 | interfaceService); |
107 | peerConnectivity.start(); | 107 | peerConnectivity.start(); |
108 | 108 | ||
109 | - routingService.addFibListener(intentSynchronizer); | 109 | + fib = new SdnIpFib(appId, interfaceService, intentSynchronizer); |
110 | - routingService.addIntentRequestListener(intentSynchronizer); | 110 | + |
111 | + routingService.addFibListener(fib); | ||
111 | routingService.start(); | 112 | routingService.start(); |
112 | 113 | ||
113 | leadershipService.addListener(leadershipEventListener); | 114 | leadershipService.addListener(leadershipEventListener); |
... | @@ -131,6 +132,11 @@ public class SdnIp implements SdnIpService { | ... | @@ -131,6 +132,11 @@ public class SdnIp implements SdnIpService { |
131 | intentSynchronizer.leaderChanged(isPrimary); | 132 | intentSynchronizer.leaderChanged(isPrimary); |
132 | } | 133 | } |
133 | 134 | ||
135 | + @Override | ||
136 | + public IntentSynchronizationService getIntentSynchronizationService() { | ||
137 | + return intentSynchronizer; | ||
138 | + } | ||
139 | + | ||
134 | /** | 140 | /** |
135 | * Converts DPIDs of the form xx:xx:xx:xx:xx:xx:xx to OpenFlow provider | 141 | * Converts DPIDs of the form xx:xx:xx:xx:xx:xx:xx to OpenFlow provider |
136 | * device URIs. | 142 | * device URIs. | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.sdnip; | ||
18 | + | ||
19 | +import com.google.common.collect.ImmutableList; | ||
20 | +import org.onlab.packet.Ethernet; | ||
21 | +import org.onlab.packet.IpAddress; | ||
22 | +import org.onlab.packet.IpPrefix; | ||
23 | +import org.onlab.packet.MacAddress; | ||
24 | +import org.onlab.packet.VlanId; | ||
25 | +import org.onosproject.core.ApplicationId; | ||
26 | +import org.onosproject.incubator.net.intf.Interface; | ||
27 | +import org.onosproject.incubator.net.intf.InterfaceService; | ||
28 | +import org.onosproject.net.ConnectPoint; | ||
29 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
30 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
31 | +import org.onosproject.net.flow.TrafficSelector; | ||
32 | +import org.onosproject.net.flow.TrafficTreatment; | ||
33 | +import org.onosproject.net.intent.Constraint; | ||
34 | +import org.onosproject.net.intent.Key; | ||
35 | +import org.onosproject.net.intent.MultiPointToSinglePointIntent; | ||
36 | +import org.onosproject.net.intent.constraint.PartialFailureConstraint; | ||
37 | +import org.onosproject.routing.FibListener; | ||
38 | +import org.onosproject.routing.FibUpdate; | ||
39 | +import org.onosproject.routing.IntentSynchronizationService; | ||
40 | +import org.slf4j.Logger; | ||
41 | +import org.slf4j.LoggerFactory; | ||
42 | + | ||
43 | +import java.util.Collection; | ||
44 | +import java.util.HashSet; | ||
45 | +import java.util.Map; | ||
46 | +import java.util.Set; | ||
47 | +import java.util.concurrent.ConcurrentHashMap; | ||
48 | + | ||
49 | +import static com.google.common.base.Preconditions.checkArgument; | ||
50 | + | ||
51 | +/** | ||
52 | + * FIB component of SDN-IP. | ||
53 | + */ | ||
54 | +public class SdnIpFib implements FibListener { | ||
55 | + private Logger log = LoggerFactory.getLogger(getClass()); | ||
56 | + | ||
57 | + private static final int PRIORITY_OFFSET = 100; | ||
58 | + private static final int PRIORITY_MULTIPLIER = 5; | ||
59 | + protected static final ImmutableList<Constraint> CONSTRAINTS | ||
60 | + = ImmutableList.of(new PartialFailureConstraint()); | ||
61 | + | ||
62 | + private final Map<IpPrefix, MultiPointToSinglePointIntent> routeIntents; | ||
63 | + | ||
64 | + private final ApplicationId appId; | ||
65 | + private final InterfaceService interfaceService; | ||
66 | + private final IntentSynchronizationService intentSynchronizer; | ||
67 | + | ||
68 | + /** | ||
69 | + * Class constructor. | ||
70 | + * | ||
71 | + * @param appId application ID to use when generating intents | ||
72 | + * @param interfaceService interface service | ||
73 | + * @param intentSynchronizer intent synchronizer | ||
74 | + */ | ||
75 | + public SdnIpFib(ApplicationId appId, InterfaceService interfaceService, | ||
76 | + IntentSynchronizationService intentSynchronizer) { | ||
77 | + routeIntents = new ConcurrentHashMap<>(); | ||
78 | + | ||
79 | + this.appId = appId; | ||
80 | + this.interfaceService = interfaceService; | ||
81 | + this.intentSynchronizer = intentSynchronizer; | ||
82 | + } | ||
83 | + | ||
84 | + | ||
85 | + @Override | ||
86 | + public void update(Collection<FibUpdate> updates, Collection<FibUpdate> withdraws) { | ||
87 | + int submitCount = 0, withdrawCount = 0; | ||
88 | + // | ||
89 | + // NOTE: Semantically, we MUST withdraw existing intents before | ||
90 | + // submitting new intents. | ||
91 | + // | ||
92 | + synchronized (this) { | ||
93 | + MultiPointToSinglePointIntent intent; | ||
94 | + | ||
95 | + // | ||
96 | + // Prepare the Intent batch operations for the intents to withdraw | ||
97 | + // | ||
98 | + for (FibUpdate withdraw : withdraws) { | ||
99 | + checkArgument(withdraw.type() == FibUpdate.Type.DELETE, | ||
100 | + "FibUpdate with wrong type in withdraws list"); | ||
101 | + | ||
102 | + IpPrefix prefix = withdraw.entry().prefix(); | ||
103 | + intent = routeIntents.remove(prefix); | ||
104 | + if (intent == null) { | ||
105 | + log.trace("SDN-IP No intent in routeIntents to delete " + | ||
106 | + "for prefix: {}", prefix); | ||
107 | + continue; | ||
108 | + } | ||
109 | + intentSynchronizer.withdraw(intent); | ||
110 | + withdrawCount++; | ||
111 | + } | ||
112 | + | ||
113 | + // | ||
114 | + // Prepare the Intent batch operations for the intents to submit | ||
115 | + // | ||
116 | + for (FibUpdate update : updates) { | ||
117 | + checkArgument(update.type() == FibUpdate.Type.UPDATE, | ||
118 | + "FibUpdate with wrong type in updates list"); | ||
119 | + | ||
120 | + IpPrefix prefix = update.entry().prefix(); | ||
121 | + intent = generateRouteIntent(prefix, update.entry().nextHopIp(), | ||
122 | + update.entry().nextHopMac()); | ||
123 | + | ||
124 | + if (intent == null) { | ||
125 | + // This preserves the old semantics - if an intent can't be | ||
126 | + // generated, we don't do anything with that prefix. But | ||
127 | + // perhaps we should withdraw the old intent anyway? | ||
128 | + continue; | ||
129 | + } | ||
130 | + | ||
131 | + routeIntents.put(prefix, intent); | ||
132 | + intentSynchronizer.submit(intent); | ||
133 | + submitCount++; | ||
134 | + } | ||
135 | + | ||
136 | + log.debug("SDN-IP submitted {}/{}, withdrew = {}/{}", submitCount, | ||
137 | + updates.size(), withdrawCount, withdraws.size()); | ||
138 | + } | ||
139 | + } | ||
140 | + | ||
141 | + /** | ||
142 | + * Generates a route intent for a prefix, the next hop IP address, and | ||
143 | + * the next hop MAC address. | ||
144 | + * <p/> | ||
145 | + * This method will find the egress interface for the intent. | ||
146 | + * Intent will match dst IP prefix and rewrite dst MAC address at all other | ||
147 | + * border switches, then forward packets according to dst MAC address. | ||
148 | + * | ||
149 | + * @param prefix IP prefix of the route to add | ||
150 | + * @param nextHopIpAddress IP address of the next hop | ||
151 | + * @param nextHopMacAddress MAC address of the next hop | ||
152 | + * @return the generated intent, or null if no intent should be submitted | ||
153 | + */ | ||
154 | + private MultiPointToSinglePointIntent generateRouteIntent( | ||
155 | + IpPrefix prefix, | ||
156 | + IpAddress nextHopIpAddress, | ||
157 | + MacAddress nextHopMacAddress) { | ||
158 | + | ||
159 | + // Find the attachment point (egress interface) of the next hop | ||
160 | + Interface egressInterface = interfaceService.getMatchingInterface(nextHopIpAddress); | ||
161 | + if (egressInterface == null) { | ||
162 | + log.warn("No outgoing interface found for {}", | ||
163 | + nextHopIpAddress); | ||
164 | + return null; | ||
165 | + } | ||
166 | + | ||
167 | + // Generate the intent itself | ||
168 | + Set<ConnectPoint> ingressPorts = new HashSet<>(); | ||
169 | + ConnectPoint egressPort = egressInterface.connectPoint(); | ||
170 | + log.debug("Generating intent for prefix {}, next hop mac {}", | ||
171 | + prefix, nextHopMacAddress); | ||
172 | + | ||
173 | + for (Interface intf : interfaceService.getInterfaces()) { | ||
174 | + // TODO this should be only peering interfaces | ||
175 | + if (!intf.connectPoint().equals(egressInterface.connectPoint())) { | ||
176 | + ConnectPoint srcPort = intf.connectPoint(); | ||
177 | + ingressPorts.add(srcPort); | ||
178 | + } | ||
179 | + } | ||
180 | + | ||
181 | + // Match the destination IP prefix at the first hop | ||
182 | + TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); | ||
183 | + if (prefix.isIp4()) { | ||
184 | + selector.matchEthType(Ethernet.TYPE_IPV4); | ||
185 | + selector.matchIPDst(prefix); | ||
186 | + } else { | ||
187 | + selector.matchEthType(Ethernet.TYPE_IPV6); | ||
188 | + selector.matchIPv6Dst(prefix); | ||
189 | + } | ||
190 | + | ||
191 | + // Rewrite the destination MAC address | ||
192 | + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder() | ||
193 | + .setEthDst(nextHopMacAddress); | ||
194 | + if (!egressInterface.vlan().equals(VlanId.NONE)) { | ||
195 | + treatment.setVlanId(egressInterface.vlan()); | ||
196 | + // If we set VLAN ID, we have to make sure a VLAN tag exists. | ||
197 | + // TODO support no VLAN -> VLAN routing | ||
198 | + selector.matchVlanId(VlanId.ANY); | ||
199 | + } | ||
200 | + | ||
201 | + int priority = | ||
202 | + prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET; | ||
203 | + Key key = Key.of(prefix.toString(), appId); | ||
204 | + return MultiPointToSinglePointIntent.builder() | ||
205 | + .appId(appId) | ||
206 | + .key(key) | ||
207 | + .selector(selector.build()) | ||
208 | + .treatment(treatment.build()) | ||
209 | + .ingressPoints(ingressPorts) | ||
210 | + .egressPoint(egressPort) | ||
211 | + .priority(priority) | ||
212 | + .constraints(CONSTRAINTS) | ||
213 | + .build(); | ||
214 | + } | ||
215 | + | ||
216 | +} |
... | @@ -18,7 +18,7 @@ package org.onosproject.sdnip.cli; | ... | @@ -18,7 +18,7 @@ package org.onosproject.sdnip.cli; |
18 | import org.apache.karaf.shell.commands.Argument; | 18 | import org.apache.karaf.shell.commands.Argument; |
19 | import org.apache.karaf.shell.commands.Command; | 19 | import org.apache.karaf.shell.commands.Command; |
20 | import org.onosproject.cli.AbstractShellCommand; | 20 | import org.onosproject.cli.AbstractShellCommand; |
21 | -import org.onosproject.sdnip.SdnIpService; | 21 | +import org.onosproject.routing.SdnIpService; |
22 | 22 | ||
23 | /** | 23 | /** |
24 | * Command to change whether this SDNIP instance is primary or not. | 24 | * Command to change whether this SDNIP instance is primary or not. | ... | ... |
... | @@ -16,6 +16,7 @@ | ... | @@ -16,6 +16,7 @@ |
16 | package org.onosproject.sdnip; | 16 | package org.onosproject.sdnip; |
17 | 17 | ||
18 | import com.google.common.collect.Sets; | 18 | import com.google.common.collect.Sets; |
19 | +import com.google.common.util.concurrent.MoreExecutors; | ||
19 | import org.junit.Before; | 20 | import org.junit.Before; |
20 | import org.junit.Test; | 21 | import org.junit.Test; |
21 | import org.onlab.junit.TestUtils; | 22 | import org.onlab.junit.TestUtils; |
... | @@ -27,10 +28,9 @@ import org.onlab.packet.IpAddress; | ... | @@ -27,10 +28,9 @@ import org.onlab.packet.IpAddress; |
27 | import org.onlab.packet.IpPrefix; | 28 | import org.onlab.packet.IpPrefix; |
28 | import org.onlab.packet.MacAddress; | 29 | import org.onlab.packet.MacAddress; |
29 | import org.onlab.packet.VlanId; | 30 | import org.onlab.packet.VlanId; |
31 | +import org.onosproject.TestApplicationId; | ||
30 | import org.onosproject.core.ApplicationId; | 32 | import org.onosproject.core.ApplicationId; |
31 | -import org.onosproject.net.config.NetworkConfigService; | ||
32 | import org.onosproject.incubator.net.intf.Interface; | 33 | import org.onosproject.incubator.net.intf.Interface; |
33 | -import org.onosproject.incubator.net.intf.InterfaceService; | ||
34 | import org.onosproject.net.ConnectPoint; | 34 | import org.onosproject.net.ConnectPoint; |
35 | import org.onosproject.net.DeviceId; | 35 | import org.onosproject.net.DeviceId; |
36 | import org.onosproject.net.PortNumber; | 36 | import org.onosproject.net.PortNumber; |
... | @@ -43,20 +43,13 @@ import org.onosproject.net.intent.AbstractIntentTest; | ... | @@ -43,20 +43,13 @@ import org.onosproject.net.intent.AbstractIntentTest; |
43 | import org.onosproject.net.intent.Intent; | 43 | import org.onosproject.net.intent.Intent; |
44 | import org.onosproject.net.intent.IntentService; | 44 | import org.onosproject.net.intent.IntentService; |
45 | import org.onosproject.net.intent.IntentState; | 45 | import org.onosproject.net.intent.IntentState; |
46 | +import org.onosproject.net.intent.Key; | ||
46 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; | 47 | import org.onosproject.net.intent.MultiPointToSinglePointIntent; |
47 | -import org.onosproject.routing.FibEntry; | ||
48 | -import org.onosproject.routing.FibUpdate; | ||
49 | import org.onosproject.routing.RouteEntry; | 48 | import org.onosproject.routing.RouteEntry; |
50 | -import org.onosproject.routing.config.BgpPeer; | ||
51 | -import org.onosproject.routing.config.RoutingConfigurationService; | ||
52 | -import org.onosproject.sdnip.IntentSynchronizer.IntentKey; | ||
53 | 49 | ||
54 | import java.util.Collections; | 50 | import java.util.Collections; |
55 | -import java.util.HashMap; | ||
56 | import java.util.HashSet; | 51 | import java.util.HashSet; |
57 | -import java.util.Map; | ||
58 | import java.util.Set; | 52 | import java.util.Set; |
59 | -import java.util.concurrent.ConcurrentHashMap; | ||
60 | 53 | ||
61 | import static org.easymock.EasyMock.createMock; | 54 | import static org.easymock.EasyMock.createMock; |
62 | import static org.easymock.EasyMock.expect; | 55 | import static org.easymock.EasyMock.expect; |
... | @@ -64,11 +57,8 @@ import static org.easymock.EasyMock.replay; | ... | @@ -64,11 +57,8 @@ import static org.easymock.EasyMock.replay; |
64 | import static org.easymock.EasyMock.reset; | 57 | import static org.easymock.EasyMock.reset; |
65 | import static org.easymock.EasyMock.verify; | 58 | import static org.easymock.EasyMock.verify; |
66 | import static org.hamcrest.Matchers.is; | 59 | import static org.hamcrest.Matchers.is; |
67 | -import static org.junit.Assert.assertEquals; | ||
68 | import static org.junit.Assert.assertFalse; | 60 | import static org.junit.Assert.assertFalse; |
69 | import static org.junit.Assert.assertThat; | 61 | import static org.junit.Assert.assertThat; |
70 | -import static org.junit.Assert.assertTrue; | ||
71 | -import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; | ||
72 | 62 | ||
73 | /** | 63 | /** |
74 | * This class tests the intent synchronization function in the | 64 | * This class tests the intent synchronization function in the |
... | @@ -76,10 +66,7 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; | ... | @@ -76,10 +66,7 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; |
76 | */ | 66 | */ |
77 | public class IntentSyncTest extends AbstractIntentTest { | 67 | public class IntentSyncTest extends AbstractIntentTest { |
78 | 68 | ||
79 | - private RoutingConfigurationService routingConfig; | ||
80 | - private InterfaceService interfaceService; | ||
81 | private IntentService intentService; | 69 | private IntentService intentService; |
82 | - private NetworkConfigService configService; | ||
83 | 70 | ||
84 | private static final ConnectPoint SW1_ETH1 = new ConnectPoint( | 71 | private static final ConnectPoint SW1_ETH1 = new ConnectPoint( |
85 | DeviceId.deviceId("of:0000000000000001"), | 72 | DeviceId.deviceId("of:0000000000000001"), |
... | @@ -100,65 +87,18 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -100,65 +87,18 @@ public class IntentSyncTest extends AbstractIntentTest { |
100 | private IntentSynchronizer intentSynchronizer; | 87 | private IntentSynchronizer intentSynchronizer; |
101 | private final Set<Interface> interfaces = Sets.newHashSet(); | 88 | private final Set<Interface> interfaces = Sets.newHashSet(); |
102 | 89 | ||
103 | - private static final ApplicationId APPID = new ApplicationId() { | 90 | + private static final ApplicationId APPID = TestApplicationId.create("SDNIP"); |
104 | - @Override | ||
105 | - public short id() { | ||
106 | - return 1; | ||
107 | - } | ||
108 | - | ||
109 | - @Override | ||
110 | - public String name() { | ||
111 | - return "SDNIP"; | ||
112 | - } | ||
113 | - }; | ||
114 | 91 | ||
115 | @Before | 92 | @Before |
116 | public void setUp() throws Exception { | 93 | public void setUp() throws Exception { |
117 | super.setUp(); | 94 | super.setUp(); |
118 | 95 | ||
119 | - routingConfig = createMock(RoutingConfigurationService.class); | ||
120 | - interfaceService = createMock(InterfaceService.class); | ||
121 | - configService = createMock(NetworkConfigService.class); | ||
122 | - | ||
123 | - // These will set expectations on routingConfig | ||
124 | setUpInterfaceService(); | 96 | setUpInterfaceService(); |
125 | - setUpBgpPeers(); | ||
126 | - | ||
127 | - replay(routingConfig); | ||
128 | - replay(interfaceService); | ||
129 | 97 | ||
130 | intentService = createMock(IntentService.class); | 98 | intentService = createMock(IntentService.class); |
131 | 99 | ||
132 | intentSynchronizer = new IntentSynchronizer(APPID, intentService, | 100 | intentSynchronizer = new IntentSynchronizer(APPID, intentService, |
133 | - null, routingConfig, | 101 | + MoreExecutors.newDirectExecutorService()); |
134 | - interfaceService); | ||
135 | - } | ||
136 | - | ||
137 | - /** | ||
138 | - * Sets up BGP peers in external networks. | ||
139 | - */ | ||
140 | - private void setUpBgpPeers() { | ||
141 | - | ||
142 | - Map<IpAddress, BgpPeer> peers = new HashMap<>(); | ||
143 | - | ||
144 | - String peerSw1Eth1 = "192.168.10.1"; | ||
145 | - peers.put(IpAddress.valueOf(peerSw1Eth1), | ||
146 | - new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1)); | ||
147 | - | ||
148 | - // Two BGP peers are connected to switch 2 port 1. | ||
149 | - String peer1Sw2Eth1 = "192.168.20.1"; | ||
150 | - peers.put(IpAddress.valueOf(peer1Sw2Eth1), | ||
151 | - new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1)); | ||
152 | - | ||
153 | - String peer2Sw2Eth1 = "192.168.20.2"; | ||
154 | - peers.put(IpAddress.valueOf(peer2Sw2Eth1), | ||
155 | - new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1)); | ||
156 | - | ||
157 | - String peer1Sw4Eth1 = "192.168.40.1"; | ||
158 | - peers.put(IpAddress.valueOf(peer1Sw4Eth1), | ||
159 | - new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1)); | ||
160 | - | ||
161 | - expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); | ||
162 | } | 102 | } |
163 | 103 | ||
164 | /** | 104 | /** |
... | @@ -200,267 +140,13 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -200,267 +140,13 @@ public class IntentSyncTest extends AbstractIntentTest { |
200 | MacAddress.valueOf("00:00:00:00:00:04"), | 140 | MacAddress.valueOf("00:00:00:00:00:04"), |
201 | VlanId.vlanId((short) 1)); | 141 | VlanId.vlanId((short) 1)); |
202 | 142 | ||
203 | - expect(interfaceService.getInterfacesByPort(SW4_ETH1)).andReturn( | ||
204 | - Collections.singleton(sw4Eth1)).anyTimes(); | ||
205 | - expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.40.1"))) | ||
206 | - .andReturn(sw4Eth1).anyTimes(); | ||
207 | - | ||
208 | interfaces.add(sw4Eth1); | 143 | interfaces.add(sw4Eth1); |
209 | - | ||
210 | - expect(interfaceService.getInterfacesByPort(SW1_ETH1)).andReturn( | ||
211 | - Collections.singleton(sw1Eth1)).anyTimes(); | ||
212 | - expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.10.1"))) | ||
213 | - .andReturn(sw1Eth1).anyTimes(); | ||
214 | - expect(interfaceService.getInterfacesByPort(SW2_ETH1)).andReturn( | ||
215 | - Collections.singleton(sw2Eth1)).anyTimes(); | ||
216 | - expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.20.1"))) | ||
217 | - .andReturn(sw2Eth1).anyTimes(); | ||
218 | - expect(interfaceService.getInterfacesByPort(SW3_ETH1)).andReturn( | ||
219 | - Collections.singleton(sw3Eth1)).anyTimes(); | ||
220 | - expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.30.1"))) | ||
221 | - .andReturn(sw3Eth1).anyTimes(); | ||
222 | - expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes(); | ||
223 | - } | ||
224 | - | ||
225 | - /** | ||
226 | - * Tests adding a FIB entry to the IntentSynchronizer. | ||
227 | - * | ||
228 | - * We verify that the synchronizer records the correct state and that the | ||
229 | - * correct intent is submitted to the IntentService. | ||
230 | - * | ||
231 | - * @throws TestUtilsException | ||
232 | - */ | ||
233 | - @Test | ||
234 | - public void testFibAdd() throws TestUtilsException { | ||
235 | - FibEntry fibEntry = new FibEntry( | ||
236 | - Ip4Prefix.valueOf("1.1.1.0/24"), | ||
237 | - Ip4Address.valueOf("192.168.10.1"), | ||
238 | - MacAddress.valueOf("00:00:00:00:00:01")); | ||
239 | - | ||
240 | - // Construct a MultiPointToSinglePointIntent intent | ||
241 | - TrafficSelector.Builder selectorBuilder = | ||
242 | - DefaultTrafficSelector.builder(); | ||
243 | - selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst( | ||
244 | - fibEntry.prefix()); | ||
245 | - | ||
246 | - TrafficTreatment.Builder treatmentBuilder = | ||
247 | - DefaultTrafficTreatment.builder(); | ||
248 | - treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01")); | ||
249 | - | ||
250 | - Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
251 | - ingressPoints.add(SW2_ETH1); | ||
252 | - ingressPoints.add(SW3_ETH1); | ||
253 | - ingressPoints.add(SW4_ETH1); | ||
254 | - | ||
255 | - MultiPointToSinglePointIntent intent = | ||
256 | - MultiPointToSinglePointIntent.builder() | ||
257 | - .appId(APPID) | ||
258 | - .selector(selectorBuilder.build()) | ||
259 | - .treatment(treatmentBuilder.build()) | ||
260 | - .ingressPoints(ingressPoints) | ||
261 | - .egressPoint(SW1_ETH1) | ||
262 | - .constraints(IntentSynchronizer.CONSTRAINTS) | ||
263 | - .build(); | ||
264 | - | ||
265 | - // Setup the expected intents | ||
266 | - intentService.submit(eqExceptId(intent)); | ||
267 | - replay(intentService); | ||
268 | - | ||
269 | - intentSynchronizer.leaderChanged(true); | ||
270 | - TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
271 | - | ||
272 | - FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, | ||
273 | - fibEntry); | ||
274 | - intentSynchronizer.update(Collections.singleton(fibUpdate), | ||
275 | - Collections.emptyList()); | ||
276 | - | ||
277 | - assertEquals(intentSynchronizer.getRouteIntents().size(), 1); | ||
278 | - Intent firstIntent = | ||
279 | - intentSynchronizer.getRouteIntents().iterator().next(); | ||
280 | - IntentKey firstIntentKey = new IntentKey(firstIntent); | ||
281 | - IntentKey intentKey = new IntentKey(intent); | ||
282 | - assertTrue(firstIntentKey.equals(intentKey)); | ||
283 | - verify(intentService); | ||
284 | - } | ||
285 | - | ||
286 | - /** | ||
287 | - * Tests adding a FIB entry with to a next hop in a VLAN. | ||
288 | - * | ||
289 | - * We verify that the synchronizer records the correct state and that the | ||
290 | - * correct intent is submitted to the IntentService. | ||
291 | - * | ||
292 | - * @throws TestUtilsException | ||
293 | - */ | ||
294 | - @Test | ||
295 | - public void testFibAddWithVlan() throws TestUtilsException { | ||
296 | - FibEntry fibEntry = new FibEntry( | ||
297 | - Ip4Prefix.valueOf("3.3.3.0/24"), | ||
298 | - Ip4Address.valueOf("192.168.40.1"), | ||
299 | - MacAddress.valueOf("00:00:00:00:00:04")); | ||
300 | - | ||
301 | - // Construct a MultiPointToSinglePointIntent intent | ||
302 | - TrafficSelector.Builder selectorBuilder = | ||
303 | - DefaultTrafficSelector.builder(); | ||
304 | - selectorBuilder.matchEthType(Ethernet.TYPE_IPV4) | ||
305 | - .matchIPDst(fibEntry.prefix()) | ||
306 | - .matchVlanId(VlanId.ANY); | ||
307 | - | ||
308 | - TrafficTreatment.Builder treatmentBuilder = | ||
309 | - DefaultTrafficTreatment.builder(); | ||
310 | - treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:04")) | ||
311 | - .setVlanId(VlanId.vlanId((short) 1)); | ||
312 | - | ||
313 | - Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
314 | - ingressPoints.add(SW1_ETH1); | ||
315 | - ingressPoints.add(SW2_ETH1); | ||
316 | - ingressPoints.add(SW3_ETH1); | ||
317 | - | ||
318 | - MultiPointToSinglePointIntent intent = | ||
319 | - MultiPointToSinglePointIntent.builder() | ||
320 | - .appId(APPID) | ||
321 | - .selector(selectorBuilder.build()) | ||
322 | - .treatment(treatmentBuilder.build()) | ||
323 | - .ingressPoints(ingressPoints) | ||
324 | - .egressPoint(SW4_ETH1) | ||
325 | - .constraints(IntentSynchronizer.CONSTRAINTS) | ||
326 | - .build(); | ||
327 | - | ||
328 | - // Setup the expected intents | ||
329 | - intentService.submit(eqExceptId(intent)); | ||
330 | - | ||
331 | - replay(intentService); | ||
332 | - | ||
333 | - // Run the test | ||
334 | - intentSynchronizer.leaderChanged(true); | ||
335 | - TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
336 | - FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry); | ||
337 | - | ||
338 | - intentSynchronizer.update(Collections.singleton(fibUpdate), | ||
339 | - Collections.emptyList()); | ||
340 | - | ||
341 | - // Verify | ||
342 | - assertEquals(intentSynchronizer.getRouteIntents().size(), 1); | ||
343 | - Intent firstIntent = | ||
344 | - intentSynchronizer.getRouteIntents().iterator().next(); | ||
345 | - IntentKey firstIntentKey = new IntentKey(firstIntent); | ||
346 | - IntentKey intentKey = new IntentKey(intent); | ||
347 | - assertTrue(firstIntentKey.equals(intentKey)); | ||
348 | - verify(intentService); | ||
349 | - } | ||
350 | - | ||
351 | - /** | ||
352 | - * Tests updating a FIB entry. | ||
353 | - * | ||
354 | - * We verify that the synchronizer records the correct state and that the | ||
355 | - * correct intent is submitted to the IntentService. | ||
356 | - * | ||
357 | - * @throws TestUtilsException | ||
358 | - */ | ||
359 | - @Test | ||
360 | - public void testFibUpdate() throws TestUtilsException { | ||
361 | - // Firstly add a route | ||
362 | - testFibAdd(); | ||
363 | - | ||
364 | - Intent addedIntent = | ||
365 | - intentSynchronizer.getRouteIntents().iterator().next(); | ||
366 | - | ||
367 | - // Start to construct a new route entry and new intent | ||
368 | - FibEntry fibEntryUpdate = new FibEntry( | ||
369 | - Ip4Prefix.valueOf("1.1.1.0/24"), | ||
370 | - Ip4Address.valueOf("192.168.20.1"), | ||
371 | - MacAddress.valueOf("00:00:00:00:00:02")); | ||
372 | - | ||
373 | - // Construct a new MultiPointToSinglePointIntent intent | ||
374 | - TrafficSelector.Builder selectorBuilderNew = | ||
375 | - DefaultTrafficSelector.builder(); | ||
376 | - selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst( | ||
377 | - fibEntryUpdate.prefix()); | ||
378 | - | ||
379 | - TrafficTreatment.Builder treatmentBuilderNew = | ||
380 | - DefaultTrafficTreatment.builder(); | ||
381 | - treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02")); | ||
382 | - | ||
383 | - | ||
384 | - Set<ConnectPoint> ingressPointsNew = new HashSet<>(); | ||
385 | - ingressPointsNew.add(SW1_ETH1); | ||
386 | - ingressPointsNew.add(SW3_ETH1); | ||
387 | - ingressPointsNew.add(SW4_ETH1); | ||
388 | - | ||
389 | - MultiPointToSinglePointIntent intentNew = | ||
390 | - MultiPointToSinglePointIntent.builder() | ||
391 | - .appId(APPID) | ||
392 | - .selector(selectorBuilderNew.build()) | ||
393 | - .treatment(treatmentBuilderNew.build()) | ||
394 | - .ingressPoints(ingressPointsNew) | ||
395 | - .egressPoint(SW2_ETH1) | ||
396 | - .constraints(IntentSynchronizer.CONSTRAINTS) | ||
397 | - .build(); | ||
398 | - | ||
399 | - // Set up test expectation | ||
400 | - reset(intentService); | ||
401 | - // Setup the expected intents | ||
402 | - intentService.withdraw(eqExceptId(addedIntent)); | ||
403 | - intentService.submit(eqExceptId(intentNew)); | ||
404 | - replay(intentService); | ||
405 | - | ||
406 | - // Call the update() method in IntentSynchronizer class | ||
407 | - intentSynchronizer.leaderChanged(true); | ||
408 | - TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
409 | - FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, | ||
410 | - fibEntryUpdate); | ||
411 | - intentSynchronizer.update(Collections.singletonList(fibUpdate), | ||
412 | - Collections.emptyList()); | ||
413 | - | ||
414 | - // Verify | ||
415 | - assertEquals(intentSynchronizer.getRouteIntents().size(), 1); | ||
416 | - Intent firstIntent = | ||
417 | - intentSynchronizer.getRouteIntents().iterator().next(); | ||
418 | - IntentKey firstIntentKey = new IntentKey(firstIntent); | ||
419 | - IntentKey intentNewKey = new IntentKey(intentNew); | ||
420 | - assertTrue(firstIntentKey.equals(intentNewKey)); | ||
421 | - verify(intentService); | ||
422 | } | 144 | } |
423 | 145 | ||
424 | /** | 146 | /** |
425 | - * Tests deleting a FIB entry. | 147 | + * Tests the synchronization behavior of intent synchronizer. We set up |
426 | - * | 148 | + * a discrepancy between the intent service state and the intent |
427 | - * We verify that the synchronizer records the correct state and that the | 149 | + * synchronizer's state and ensure that this is reconciled correctly. |
428 | - * correct intent is withdrawn from the IntentService. | ||
429 | - * | ||
430 | - * @throws TestUtilsException | ||
431 | - */ | ||
432 | - @Test | ||
433 | - public void testFibDelete() throws TestUtilsException { | ||
434 | - // Firstly add a route | ||
435 | - testFibAdd(); | ||
436 | - | ||
437 | - Intent addedIntent = | ||
438 | - intentSynchronizer.getRouteIntents().iterator().next(); | ||
439 | - | ||
440 | - // Construct the existing route entry | ||
441 | - FibEntry fibEntry = new FibEntry( | ||
442 | - Ip4Prefix.valueOf("1.1.1.0/24"), null, null); | ||
443 | - | ||
444 | - // Set up expectation | ||
445 | - reset(intentService); | ||
446 | - // Setup the expected intents | ||
447 | - intentService.withdraw(eqExceptId(addedIntent)); | ||
448 | - replay(intentService); | ||
449 | - | ||
450 | - // Call the update() method in IntentSynchronizer class | ||
451 | - intentSynchronizer.leaderChanged(true); | ||
452 | - TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
453 | - FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry); | ||
454 | - intentSynchronizer.update(Collections.emptyList(), | ||
455 | - Collections.singletonList(fibUpdate)); | ||
456 | - | ||
457 | - // Verify | ||
458 | - assertEquals(intentSynchronizer.getRouteIntents().size(), 0); | ||
459 | - verify(intentService); | ||
460 | - } | ||
461 | - | ||
462 | - /** | ||
463 | - * This method tests the behavior of intent Synchronizer. | ||
464 | * | 150 | * |
465 | * @throws TestUtilsException | 151 | * @throws TestUtilsException |
466 | */ | 152 | */ |
... | @@ -529,27 +215,13 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -529,27 +215,13 @@ public class IntentSyncTest extends AbstractIntentTest { |
529 | // Compose a intent, which is equal to intent5 but the id is different. | 215 | // Compose a intent, which is equal to intent5 but the id is different. |
530 | MultiPointToSinglePointIntent intent5New = | 216 | MultiPointToSinglePointIntent intent5New = |
531 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); | 217 | staticIntentBuilder(intent5, routeEntry5, "00:00:00:00:00:01"); |
532 | - assertThat(IntentSynchronizer.IntentKey.equalIntents( | 218 | + assertThat(IntentUtils.equals(intent5, intent5New), is(true)); |
533 | - intent5, intent5New), | ||
534 | - is(true)); | ||
535 | assertFalse(intent5.equals(intent5New)); | 219 | assertFalse(intent5.equals(intent5New)); |
536 | 220 | ||
537 | MultiPointToSinglePointIntent intent6 = intentBuilder( | 221 | MultiPointToSinglePointIntent intent6 = intentBuilder( |
538 | routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1); | 222 | routeEntry6.prefix(), "00:00:00:00:00:01", SW1_ETH1); |
539 | 223 | ||
540 | - // Set up the routeIntents field in IntentSynchronizer class | ||
541 | - ConcurrentHashMap<IpPrefix, MultiPointToSinglePointIntent> | ||
542 | - routeIntents = new ConcurrentHashMap<>(); | ||
543 | - routeIntents.put(routeEntry1.prefix(), intent1); | ||
544 | - routeIntents.put(routeEntry3.prefix(), intent3); | ||
545 | - routeIntents.put(routeEntry4Update.prefix(), intent4Update); | ||
546 | - routeIntents.put(routeEntry5.prefix(), intent5New); | ||
547 | - routeIntents.put(routeEntry6.prefix(), intent6); | ||
548 | - routeIntents.put(routeEntry7.prefix(), intent7); | ||
549 | - TestUtils.setField(intentSynchronizer, "routeIntents", routeIntents); | ||
550 | - | ||
551 | // Set up expectation | 224 | // Set up expectation |
552 | - reset(intentService); | ||
553 | Set<Intent> intents = new HashSet<>(); | 225 | Set<Intent> intents = new HashSet<>(); |
554 | intents.add(intent1); | 226 | intents.add(intent1); |
555 | expect(intentService.getIntentState(intent1.key())) | 227 | expect(intentService.getIntentState(intent1.key())) |
... | @@ -568,9 +240,9 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -568,9 +240,9 @@ public class IntentSyncTest extends AbstractIntentTest { |
568 | .andReturn(IntentState.WITHDRAWING).anyTimes(); | 240 | .andReturn(IntentState.WITHDRAWING).anyTimes(); |
569 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); | 241 | expect(intentService.getIntents()).andReturn(intents).anyTimes(); |
570 | 242 | ||
243 | + // These are the operations that should be done to the intentService | ||
244 | + // during synchronization | ||
571 | intentService.withdraw(intent2); | 245 | intentService.withdraw(intent2); |
572 | - intentService.withdraw(intent4); | ||
573 | - | ||
574 | intentService.submit(intent3); | 246 | intentService.submit(intent3); |
575 | intentService.submit(intent4Update); | 247 | intentService.submit(intent4Update); |
576 | intentService.submit(intent6); | 248 | intentService.submit(intent6); |
... | @@ -578,16 +250,101 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -578,16 +250,101 @@ public class IntentSyncTest extends AbstractIntentTest { |
578 | replay(intentService); | 250 | replay(intentService); |
579 | 251 | ||
580 | // Start the test | 252 | // Start the test |
253 | + | ||
254 | + // Simulate some input from the clients. The intent synchronizer has not | ||
255 | + // gained the global leadership yet, but it will remember this input for | ||
256 | + // when it does. | ||
257 | + intentSynchronizer.submit(intent1); | ||
258 | + intentSynchronizer.submit(intent2); | ||
259 | + intentSynchronizer.withdraw(intent2); | ||
260 | + intentSynchronizer.submit(intent3); | ||
261 | + intentSynchronizer.submit(intent4); | ||
262 | + intentSynchronizer.submit(intent4Update); | ||
263 | + intentSynchronizer.submit(intent5); | ||
264 | + intentSynchronizer.submit(intent6); | ||
265 | + intentSynchronizer.submit(intent7); | ||
266 | + | ||
267 | + // Give the leadership to the intent synchronizer. It will now attempt | ||
268 | + // to synchronize the intents in the store with the intents it has | ||
269 | + // recorded based on the earlier user input. | ||
270 | + intentSynchronizer.leaderChanged(true); | ||
271 | + | ||
272 | + verify(intentService); | ||
273 | + } | ||
274 | + | ||
275 | + /** | ||
276 | + * Tests the behavior of the submit API, both when the synchronizer has | ||
277 | + * leadership and when it does not. | ||
278 | + */ | ||
279 | + @Test | ||
280 | + public void testSubmit() { | ||
281 | + IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24"); | ||
282 | + Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1); | ||
283 | + | ||
284 | + // Set up expectations | ||
285 | + intentService.submit(intent); | ||
286 | + expect(intentService.getIntents()).andReturn(Collections.emptyList()) | ||
287 | + .anyTimes(); | ||
288 | + replay(intentService); | ||
289 | + | ||
290 | + // Give the intent synchronizer leadership so it will submit intents | ||
291 | + // to the intent service | ||
292 | + intentSynchronizer.leaderChanged(true); | ||
293 | + | ||
294 | + // Test the submit | ||
295 | + intentSynchronizer.submit(intent); | ||
296 | + | ||
297 | + verify(intentService); | ||
298 | + | ||
299 | + // Now we'll remove leadership from the intent synchronizer and verify | ||
300 | + // that it does not submit any intents to the intent service when we | ||
301 | + // call the submit API | ||
302 | + reset(intentService); | ||
303 | + replay(intentService); | ||
304 | + | ||
305 | + intentSynchronizer.leaderChanged(false); | ||
306 | + | ||
307 | + intentSynchronizer.submit(intent); | ||
308 | + | ||
309 | + verify(intentService); | ||
310 | + } | ||
311 | + | ||
312 | + /** | ||
313 | + * Tests the behavior of the withdraw API, both when the synchronizer has | ||
314 | + * leadership and when it does not. | ||
315 | + */ | ||
316 | + @Test | ||
317 | + public void testWithdraw() { | ||
318 | + IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24"); | ||
319 | + Intent intent = intentBuilder(prefix, "00:00:00:00:00:01", SW1_ETH1); | ||
320 | + | ||
321 | + // Submit an intent first so we can withdraw it later | ||
322 | + intentService.submit(intent); | ||
323 | + intentService.withdraw(intent); | ||
324 | + expect(intentService.getIntents()).andReturn(Collections.emptyList()) | ||
325 | + .anyTimes(); | ||
326 | + replay(intentService); | ||
327 | + | ||
328 | + // Give the intent synchronizer leadership so it will submit intents | ||
329 | + // to the intent service | ||
581 | intentSynchronizer.leaderChanged(true); | 330 | intentSynchronizer.leaderChanged(true); |
582 | - intentSynchronizer.synchronizeIntents(); | ||
583 | 331 | ||
584 | - // Verify | 332 | + // Test the submit then withdraw |
585 | - assertEquals(intentSynchronizer.getRouteIntents().size(), 6); | 333 | + intentSynchronizer.submit(intent); |
586 | - assertTrue(intentSynchronizer.getRouteIntents().contains(intent1)); | 334 | + intentSynchronizer.withdraw(intent); |
587 | - assertTrue(intentSynchronizer.getRouteIntents().contains(intent3)); | 335 | + |
588 | - assertTrue(intentSynchronizer.getRouteIntents().contains(intent4Update)); | 336 | + verify(intentService); |
589 | - assertTrue(intentSynchronizer.getRouteIntents().contains(intent5)); | 337 | + |
590 | - assertTrue(intentSynchronizer.getRouteIntents().contains(intent6)); | 338 | + // Now we'll remove leadership from the intent synchronizer and verify |
339 | + // that it does not withdraw any intents to the intent service when we | ||
340 | + // call the withdraw API | ||
341 | + reset(intentService); | ||
342 | + replay(intentService); | ||
343 | + | ||
344 | + intentSynchronizer.leaderChanged(false); | ||
345 | + | ||
346 | + intentSynchronizer.submit(intent); | ||
347 | + intentSynchronizer.withdraw(intent); | ||
591 | 348 | ||
592 | verify(intentService); | 349 | verify(intentService); |
593 | } | 350 | } |
... | @@ -607,10 +364,10 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -607,10 +364,10 @@ public class IntentSyncTest extends AbstractIntentTest { |
607 | TrafficSelector.Builder selectorBuilder = | 364 | TrafficSelector.Builder selectorBuilder = |
608 | DefaultTrafficSelector.builder(); | 365 | DefaultTrafficSelector.builder(); |
609 | if (ipPrefix.isIp4()) { | 366 | if (ipPrefix.isIp4()) { |
610 | - selectorBuilder.matchEthType(Ethernet.TYPE_IPV4); // IPv4 | 367 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV4); |
611 | selectorBuilder.matchIPDst(ipPrefix); | 368 | selectorBuilder.matchIPDst(ipPrefix); |
612 | } else { | 369 | } else { |
613 | - selectorBuilder.matchEthType(Ethernet.TYPE_IPV6); // IPv6 | 370 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV6); |
614 | selectorBuilder.matchIPv6Dst(ipPrefix); | 371 | selectorBuilder.matchIPv6Dst(ipPrefix); |
615 | } | 372 | } |
616 | 373 | ||
... | @@ -628,11 +385,12 @@ public class IntentSyncTest extends AbstractIntentTest { | ... | @@ -628,11 +385,12 @@ public class IntentSyncTest extends AbstractIntentTest { |
628 | MultiPointToSinglePointIntent intent = | 385 | MultiPointToSinglePointIntent intent = |
629 | MultiPointToSinglePointIntent.builder() | 386 | MultiPointToSinglePointIntent.builder() |
630 | .appId(APPID) | 387 | .appId(APPID) |
388 | + .key(Key.of(ipPrefix.toString(), APPID)) | ||
631 | .selector(selectorBuilder.build()) | 389 | .selector(selectorBuilder.build()) |
632 | .treatment(treatmentBuilder.build()) | 390 | .treatment(treatmentBuilder.build()) |
633 | .ingressPoints(ingressPoints) | 391 | .ingressPoints(ingressPoints) |
634 | .egressPoint(egressPoint) | 392 | .egressPoint(egressPoint) |
635 | - .constraints(IntentSynchronizer.CONSTRAINTS) | 393 | + .constraints(SdnIpFib.CONSTRAINTS) |
636 | .build(); | 394 | .build(); |
637 | return intent; | 395 | return intent; |
638 | } | 396 | } | ... | ... |
... | @@ -19,7 +19,6 @@ import com.google.common.collect.Sets; | ... | @@ -19,7 +19,6 @@ import com.google.common.collect.Sets; |
19 | import org.junit.Before; | 19 | import org.junit.Before; |
20 | import org.junit.Ignore; | 20 | import org.junit.Ignore; |
21 | import org.junit.Test; | 21 | import org.junit.Test; |
22 | -import org.onlab.junit.TestUtils; | ||
23 | import org.onlab.junit.TestUtils.TestUtilsException; | 22 | import org.onlab.junit.TestUtils.TestUtilsException; |
24 | import org.onlab.packet.Ethernet; | 23 | import org.onlab.packet.Ethernet; |
25 | import org.onlab.packet.IPv4; | 24 | import org.onlab.packet.IPv4; |
... | @@ -28,13 +27,14 @@ import org.onlab.packet.IpPrefix; | ... | @@ -28,13 +27,14 @@ import org.onlab.packet.IpPrefix; |
28 | import org.onlab.packet.MacAddress; | 27 | import org.onlab.packet.MacAddress; |
29 | import org.onlab.packet.TpPort; | 28 | import org.onlab.packet.TpPort; |
30 | import org.onlab.packet.VlanId; | 29 | import org.onlab.packet.VlanId; |
30 | +import org.onosproject.TestApplicationId; | ||
31 | import org.onosproject.core.ApplicationId; | 31 | import org.onosproject.core.ApplicationId; |
32 | -import org.onosproject.net.config.NetworkConfigService; | ||
33 | import org.onosproject.incubator.net.intf.Interface; | 32 | import org.onosproject.incubator.net.intf.Interface; |
34 | import org.onosproject.incubator.net.intf.InterfaceService; | 33 | import org.onosproject.incubator.net.intf.InterfaceService; |
35 | import org.onosproject.net.ConnectPoint; | 34 | import org.onosproject.net.ConnectPoint; |
36 | import org.onosproject.net.DeviceId; | 35 | import org.onosproject.net.DeviceId; |
37 | import org.onosproject.net.PortNumber; | 36 | import org.onosproject.net.PortNumber; |
37 | +import org.onosproject.net.config.NetworkConfigService; | ||
38 | import org.onosproject.net.flow.DefaultTrafficSelector; | 38 | import org.onosproject.net.flow.DefaultTrafficSelector; |
39 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 39 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
40 | import org.onosproject.net.flow.TrafficSelector; | 40 | import org.onosproject.net.flow.TrafficSelector; |
... | @@ -42,8 +42,9 @@ import org.onosproject.net.flow.TrafficTreatment; | ... | @@ -42,8 +42,9 @@ import org.onosproject.net.flow.TrafficTreatment; |
42 | import org.onosproject.net.host.InterfaceIpAddress; | 42 | import org.onosproject.net.host.InterfaceIpAddress; |
43 | import org.onosproject.net.intent.AbstractIntentTest; | 43 | import org.onosproject.net.intent.AbstractIntentTest; |
44 | import org.onosproject.net.intent.Intent; | 44 | import org.onosproject.net.intent.Intent; |
45 | -import org.onosproject.net.intent.IntentService; | 45 | +import org.onosproject.net.intent.Key; |
46 | import org.onosproject.net.intent.PointToPointIntent; | 46 | import org.onosproject.net.intent.PointToPointIntent; |
47 | +import org.onosproject.routing.IntentSynchronizationService; | ||
47 | import org.onosproject.routing.config.BgpConfig; | 48 | import org.onosproject.routing.config.BgpConfig; |
48 | import org.onosproject.routing.config.BgpPeer; | 49 | import org.onosproject.routing.config.BgpPeer; |
49 | import org.onosproject.routing.config.BgpSpeaker; | 50 | import org.onosproject.routing.config.BgpSpeaker; |
... | @@ -71,26 +72,15 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; | ... | @@ -71,26 +72,15 @@ import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; |
71 | */ | 72 | */ |
72 | public class PeerConnectivityManagerTest extends AbstractIntentTest { | 73 | public class PeerConnectivityManagerTest extends AbstractIntentTest { |
73 | 74 | ||
74 | - private static final ApplicationId APPID = new ApplicationId() { | 75 | + private static final ApplicationId APPID = TestApplicationId.create("foo"); |
75 | - @Override | ||
76 | - public short id() { | ||
77 | - return 0; | ||
78 | - } | ||
79 | - | ||
80 | - @Override | ||
81 | - public String name() { | ||
82 | - return "foo"; | ||
83 | - } | ||
84 | - }; | ||
85 | 76 | ||
86 | private static final ApplicationId CONFIG_APP_ID = APPID; | 77 | private static final ApplicationId CONFIG_APP_ID = APPID; |
87 | 78 | ||
88 | private PeerConnectivityManager peerConnectivityManager; | 79 | private PeerConnectivityManager peerConnectivityManager; |
89 | - private IntentSynchronizer intentSynchronizer; | 80 | + private IntentSynchronizationService intentSynchronizer; |
90 | private RoutingConfigurationService routingConfig; | 81 | private RoutingConfigurationService routingConfig; |
91 | private InterfaceService interfaceService; | 82 | private InterfaceService interfaceService; |
92 | private NetworkConfigService networkConfigService; | 83 | private NetworkConfigService networkConfigService; |
93 | - private IntentService intentService; | ||
94 | 84 | ||
95 | private Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers; | 85 | private Set<BgpConfig.BgpSpeakerConfig> bgpSpeakers; |
96 | private Map<String, Interface> interfaces; | 86 | private Map<String, Interface> interfaces; |
... | @@ -98,8 +88,6 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -98,8 +88,6 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
98 | 88 | ||
99 | private BgpConfig bgpConfig; | 89 | private BgpConfig bgpConfig; |
100 | 90 | ||
101 | - private Map<String, Interface> configuredInterfaces; | ||
102 | - private Map<IpAddress, BgpPeer> configuredPeers; | ||
103 | private List<PointToPointIntent> intentList; | 91 | private List<PointToPointIntent> intentList; |
104 | 92 | ||
105 | private final String dpid1 = "00:00:00:00:00:00:00:01"; | 93 | private final String dpid1 = "00:00:00:00:00:00:00:01"; |
... | @@ -136,7 +124,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -136,7 +124,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
136 | // These will set expectations on routingConfig and interfaceService | 124 | // These will set expectations on routingConfig and interfaceService |
137 | bgpSpeakers = setUpBgpSpeakers(); | 125 | bgpSpeakers = setUpBgpSpeakers(); |
138 | interfaces = Collections.unmodifiableMap(setUpInterfaces()); | 126 | interfaces = Collections.unmodifiableMap(setUpInterfaces()); |
139 | - peers = Collections.unmodifiableMap(setUpPeers()); | 127 | + peers = setUpPeers(); |
140 | 128 | ||
141 | initPeerConnectivity(); | 129 | initPeerConnectivity(); |
142 | intentList = setUpIntentList(); | 130 | intentList = setUpIntentList(); |
... | @@ -169,11 +157,11 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -169,11 +157,11 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
169 | * Sets up logical interfaces, which emulate the configured interfaces | 157 | * Sets up logical interfaces, which emulate the configured interfaces |
170 | * in SDN-IP application. | 158 | * in SDN-IP application. |
171 | * | 159 | * |
172 | - * @return configured interfaces as a MAP from Interface name to Interface | 160 | + * @return configured interfaces as a map from interface name to Interface |
173 | */ | 161 | */ |
174 | private Map<String, Interface> setUpInterfaces() { | 162 | private Map<String, Interface> setUpInterfaces() { |
175 | 163 | ||
176 | - configuredInterfaces = new HashMap<>(); | 164 | + Map<String, Interface> configuredInterfaces = new HashMap<>(); |
177 | 165 | ||
178 | String interfaceSw1Eth1 = "s1-eth1"; | 166 | String interfaceSw1Eth1 = "s1-eth1"; |
179 | InterfaceIpAddress ia1 = | 167 | InterfaceIpAddress ia1 = |
... | @@ -242,7 +230,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -242,7 +230,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
242 | */ | 230 | */ |
243 | private Map<IpAddress, BgpPeer> setUpPeers() { | 231 | private Map<IpAddress, BgpPeer> setUpPeers() { |
244 | 232 | ||
245 | - configuredPeers = new HashMap<>(); | 233 | + Map<IpAddress, BgpPeer> configuredPeers = new HashMap<>(); |
246 | 234 | ||
247 | String peerSw1Eth1 = "192.168.10.1"; | 235 | String peerSw1Eth1 = "192.168.10.1"; |
248 | configuredPeers.put(IpAddress.valueOf(peerSw1Eth1), | 236 | configuredPeers.put(IpAddress.valueOf(peerSw1Eth1), |
... | @@ -266,14 +254,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -266,14 +254,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
266 | * @return point to point intent list | 254 | * @return point to point intent list |
267 | */ | 255 | */ |
268 | private List<PointToPointIntent> setUpIntentList() { | 256 | private List<PointToPointIntent> setUpIntentList() { |
269 | - | ||
270 | intentList = new ArrayList<>(); | 257 | intentList = new ArrayList<>(); |
271 | 258 | ||
272 | setUpBgpIntents(); | 259 | setUpBgpIntents(); |
273 | setUpIcmpIntents(); | 260 | setUpIcmpIntents(); |
274 | 261 | ||
275 | return intentList; | 262 | return intentList; |
276 | - | ||
277 | } | 263 | } |
278 | 264 | ||
279 | /** | 265 | /** |
... | @@ -306,8 +292,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -306,8 +292,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
306 | builder.matchTcpDst(TpPort.tpPort(dstTcpPort)); | 292 | builder.matchTcpDst(TpPort.tpPort(dstTcpPort)); |
307 | } | 293 | } |
308 | 294 | ||
295 | + Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0] | ||
296 | + + "-" + ((srcTcpPort == null) ? "dst" : "src"), APPID); | ||
297 | + | ||
309 | PointToPointIntent intent = PointToPointIntent.builder() | 298 | PointToPointIntent intent = PointToPointIntent.builder() |
310 | .appId(APPID) | 299 | .appId(APPID) |
300 | + .key(key) | ||
311 | .selector(builder.build()) | 301 | .selector(builder.build()) |
312 | .treatment(noTreatment) | 302 | .treatment(noTreatment) |
313 | .ingressPoint(srcConnectPoint) | 303 | .ingressPoint(srcConnectPoint) |
... | @@ -392,8 +382,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -392,8 +382,12 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
392 | .matchIPDst(IpPrefix.valueOf(dstPrefix)) | 382 | .matchIPDst(IpPrefix.valueOf(dstPrefix)) |
393 | .build(); | 383 | .build(); |
394 | 384 | ||
385 | + Key key = Key.of(srcPrefix.split("/")[0] + "-" + dstPrefix.split("/")[0] | ||
386 | + + "-" + "icmp", APPID); | ||
387 | + | ||
395 | PointToPointIntent intent = PointToPointIntent.builder() | 388 | PointToPointIntent intent = PointToPointIntent.builder() |
396 | .appId(APPID) | 389 | .appId(APPID) |
390 | + .key(key) | ||
397 | .selector(selector) | 391 | .selector(selector) |
398 | .treatment(noTreatment) | 392 | .treatment(noTreatment) |
399 | .ingressPoint(srcConnectPoint) | 393 | .ingressPoint(srcConnectPoint) |
... | @@ -434,19 +428,14 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -434,19 +428,14 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
434 | expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); | 428 | expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); |
435 | expect(bgpConfig.bgpSpeakers()).andReturn(bgpSpeakers).anyTimes(); | 429 | expect(bgpConfig.bgpSpeakers()).andReturn(bgpSpeakers).anyTimes(); |
436 | replay(bgpConfig); | 430 | replay(bgpConfig); |
437 | - expect(networkConfigService.getConfig(APPID, BgpConfig.class)).andReturn(bgpConfig).anyTimes(); | 431 | + expect(networkConfigService.getConfig(APPID, BgpConfig.class)) |
432 | + .andReturn(bgpConfig).anyTimes(); | ||
438 | replay(networkConfigService); | 433 | replay(networkConfigService); |
439 | replay(routingConfig); | 434 | replay(routingConfig); |
440 | replay(interfaceService); | 435 | replay(interfaceService); |
441 | 436 | ||
442 | - intentService = createMock(IntentService.class); | 437 | + intentSynchronizer = createMock(IntentSynchronizationService.class); |
443 | - replay(intentService); | 438 | + replay(intentSynchronizer); |
444 | - | ||
445 | - intentSynchronizer = new IntentSynchronizer(APPID, intentService, | ||
446 | - null, routingConfig, | ||
447 | - interfaceService); | ||
448 | - intentSynchronizer.leaderChanged(true); | ||
449 | - TestUtils.setField(intentSynchronizer, "isActivatedLeader", true); | ||
450 | 439 | ||
451 | peerConnectivityManager = | 440 | peerConnectivityManager = |
452 | new PeerConnectivityManager(APPID, intentSynchronizer, | 441 | new PeerConnectivityManager(APPID, intentSynchronizer, |
... | @@ -464,20 +453,18 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -464,20 +453,18 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
464 | */ | 453 | */ |
465 | @Test | 454 | @Test |
466 | public void testConnectionSetup() { | 455 | public void testConnectionSetup() { |
467 | - | 456 | + reset(intentSynchronizer); |
468 | - reset(intentService); | ||
469 | 457 | ||
470 | // Setup the expected intents | 458 | // Setup the expected intents |
471 | for (Intent intent : intentList) { | 459 | for (Intent intent : intentList) { |
472 | - intentService.submit(eqExceptId(intent)); | 460 | + intentSynchronizer.submit(eqExceptId(intent)); |
473 | } | 461 | } |
474 | - replay(intentService); | 462 | + replay(intentSynchronizer); |
475 | 463 | ||
476 | // Running the interface to be tested. | 464 | // Running the interface to be tested. |
477 | peerConnectivityManager.start(); | 465 | peerConnectivityManager.start(); |
478 | 466 | ||
479 | - verify(intentService); | 467 | + verify(intentSynchronizer); |
480 | - | ||
481 | } | 468 | } |
482 | 469 | ||
483 | /** | 470 | /** |
... | @@ -488,7 +475,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -488,7 +475,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
488 | reset(interfaceService); | 475 | reset(interfaceService); |
489 | 476 | ||
490 | expect(interfaceService.getInterfaces()).andReturn( | 477 | expect(interfaceService.getInterfaces()).andReturn( |
491 | - Sets.<Interface>newHashSet()).anyTimes(); | 478 | + Sets.newHashSet()).anyTimes(); |
492 | expect(interfaceService.getInterfacesByPort(s2Eth1)) | 479 | expect(interfaceService.getInterfacesByPort(s2Eth1)) |
493 | .andReturn(Collections.emptySet()).anyTimes(); | 480 | .andReturn(Collections.emptySet()).anyTimes(); |
494 | expect(interfaceService.getInterfacesByPort(s1Eth1)) | 481 | expect(interfaceService.getInterfacesByPort(s1Eth1)) |
... | @@ -508,10 +495,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -508,10 +495,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
508 | 495 | ||
509 | replay(interfaceService); | 496 | replay(interfaceService); |
510 | 497 | ||
511 | - reset(intentService); | 498 | + reset(intentSynchronizer); |
512 | - replay(intentService); | 499 | + replay(intentSynchronizer); |
513 | peerConnectivityManager.start(); | 500 | peerConnectivityManager.start(); |
514 | - verify(intentService); | 501 | + verify(intentSynchronizer); |
515 | } | 502 | } |
516 | 503 | ||
517 | /** | 504 | /** |
... | @@ -527,10 +514,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -527,10 +514,10 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
527 | expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); | 514 | expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); |
528 | replay(routingConfig); | 515 | replay(routingConfig); |
529 | 516 | ||
530 | - reset(intentService); | 517 | + reset(intentSynchronizer); |
531 | - replay(intentService); | 518 | + replay(intentSynchronizer); |
532 | peerConnectivityManager.start(); | 519 | peerConnectivityManager.start(); |
533 | - verify(intentService); | 520 | + verify(intentSynchronizer); |
534 | } | 521 | } |
535 | 522 | ||
536 | /** | 523 | /** |
... | @@ -540,7 +527,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { | ... | @@ -540,7 +527,7 @@ public class PeerConnectivityManagerTest extends AbstractIntentTest { |
540 | @Test | 527 | @Test |
541 | public void testNoPeerInterface() { | 528 | public void testNoPeerInterface() { |
542 | String peerSw100Eth1 = "192.168.200.1"; | 529 | String peerSw100Eth1 = "192.168.200.1"; |
543 | - configuredPeers.put(IpAddress.valueOf(peerSw100Eth1), | 530 | + peers.put(IpAddress.valueOf(peerSw100Eth1), |
544 | new BgpPeer("00:00:00:00:00:00:01:00", 1, peerSw100Eth1)); | 531 | new BgpPeer("00:00:00:00:00:00:01:00", 1, peerSw100Eth1)); |
545 | testConnectionSetup(); | 532 | testConnectionSetup(); |
546 | } | 533 | } | ... | ... |
1 | +/* | ||
2 | + * Copyright 2015 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.sdnip; | ||
18 | + | ||
19 | +import com.google.common.collect.Sets; | ||
20 | +import org.junit.Before; | ||
21 | +import org.junit.Test; | ||
22 | +import org.onlab.packet.Ethernet; | ||
23 | +import org.onlab.packet.Ip4Address; | ||
24 | +import org.onlab.packet.Ip4Prefix; | ||
25 | +import org.onlab.packet.IpAddress; | ||
26 | +import org.onlab.packet.IpPrefix; | ||
27 | +import org.onlab.packet.MacAddress; | ||
28 | +import org.onlab.packet.VlanId; | ||
29 | +import org.onosproject.TestApplicationId; | ||
30 | +import org.onosproject.core.ApplicationId; | ||
31 | +import org.onosproject.incubator.net.intf.Interface; | ||
32 | +import org.onosproject.incubator.net.intf.InterfaceService; | ||
33 | +import org.onosproject.net.ConnectPoint; | ||
34 | +import org.onosproject.net.DeviceId; | ||
35 | +import org.onosproject.net.PortNumber; | ||
36 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
37 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
38 | +import org.onosproject.net.flow.TrafficSelector; | ||
39 | +import org.onosproject.net.flow.TrafficTreatment; | ||
40 | +import org.onosproject.net.host.InterfaceIpAddress; | ||
41 | +import org.onosproject.net.intent.AbstractIntentTest; | ||
42 | +import org.onosproject.net.intent.Key; | ||
43 | +import org.onosproject.net.intent.MultiPointToSinglePointIntent; | ||
44 | +import org.onosproject.routing.FibEntry; | ||
45 | +import org.onosproject.routing.FibUpdate; | ||
46 | +import org.onosproject.routing.IntentSynchronizationService; | ||
47 | +import org.onosproject.routing.config.BgpPeer; | ||
48 | +import org.onosproject.routing.config.RoutingConfigurationService; | ||
49 | + | ||
50 | +import java.util.Collections; | ||
51 | +import java.util.HashMap; | ||
52 | +import java.util.HashSet; | ||
53 | +import java.util.Map; | ||
54 | +import java.util.Set; | ||
55 | + | ||
56 | +import static org.easymock.EasyMock.createMock; | ||
57 | +import static org.easymock.EasyMock.expect; | ||
58 | +import static org.easymock.EasyMock.replay; | ||
59 | +import static org.easymock.EasyMock.reset; | ||
60 | +import static org.easymock.EasyMock.verify; | ||
61 | +import static org.onosproject.sdnip.TestIntentServiceHelper.eqExceptId; | ||
62 | + | ||
63 | +/** | ||
64 | + * Unit tests for SdnIpFib. | ||
65 | + */ | ||
66 | +public class SdnIpFibTest extends AbstractIntentTest { | ||
67 | + | ||
68 | + private RoutingConfigurationService routingConfig; | ||
69 | + private InterfaceService interfaceService; | ||
70 | + | ||
71 | + private static final ConnectPoint SW1_ETH1 = new ConnectPoint( | ||
72 | + DeviceId.deviceId("of:0000000000000001"), | ||
73 | + PortNumber.portNumber(1)); | ||
74 | + | ||
75 | + private static final ConnectPoint SW2_ETH1 = new ConnectPoint( | ||
76 | + DeviceId.deviceId("of:0000000000000002"), | ||
77 | + PortNumber.portNumber(1)); | ||
78 | + | ||
79 | + private static final ConnectPoint SW3_ETH1 = new ConnectPoint( | ||
80 | + DeviceId.deviceId("of:0000000000000003"), | ||
81 | + PortNumber.portNumber(1)); | ||
82 | + | ||
83 | + private static final ConnectPoint SW4_ETH1 = new ConnectPoint( | ||
84 | + DeviceId.deviceId("of:0000000000000004"), | ||
85 | + PortNumber.portNumber(1)); | ||
86 | + | ||
87 | + private SdnIpFib sdnipFib; | ||
88 | + private IntentSynchronizationService intentSynchronizer; | ||
89 | + private final Set<Interface> interfaces = Sets.newHashSet(); | ||
90 | + | ||
91 | + private static final ApplicationId APPID = TestApplicationId.create("SDNIP"); | ||
92 | + | ||
93 | + @Before | ||
94 | + public void setUp() throws Exception { | ||
95 | + super.setUp(); | ||
96 | + | ||
97 | + routingConfig = createMock(RoutingConfigurationService.class); | ||
98 | + interfaceService = createMock(InterfaceService.class); | ||
99 | + | ||
100 | + // These will set expectations on routingConfig and interfaceService | ||
101 | + setUpInterfaceService(); | ||
102 | + setUpBgpPeers(); | ||
103 | + | ||
104 | + replay(routingConfig); | ||
105 | + replay(interfaceService); | ||
106 | + | ||
107 | + intentSynchronizer = createMock(IntentSynchronizationService.class); | ||
108 | + | ||
109 | + sdnipFib = new SdnIpFib(APPID, interfaceService, intentSynchronizer); | ||
110 | + } | ||
111 | + | ||
112 | + /** | ||
113 | + * Sets up BGP peers in external networks. | ||
114 | + */ | ||
115 | + private void setUpBgpPeers() { | ||
116 | + | ||
117 | + Map<IpAddress, BgpPeer> peers = new HashMap<>(); | ||
118 | + | ||
119 | + String peerSw1Eth1 = "192.168.10.1"; | ||
120 | + peers.put(IpAddress.valueOf(peerSw1Eth1), | ||
121 | + new BgpPeer("00:00:00:00:00:00:00:01", 1, peerSw1Eth1)); | ||
122 | + | ||
123 | + // Two BGP peers are connected to switch 2 port 1. | ||
124 | + String peer1Sw2Eth1 = "192.168.20.1"; | ||
125 | + peers.put(IpAddress.valueOf(peer1Sw2Eth1), | ||
126 | + new BgpPeer("00:00:00:00:00:00:00:02", 1, peer1Sw2Eth1)); | ||
127 | + | ||
128 | + String peer2Sw2Eth1 = "192.168.20.2"; | ||
129 | + peers.put(IpAddress.valueOf(peer2Sw2Eth1), | ||
130 | + new BgpPeer("00:00:00:00:00:00:00:02", 1, peer2Sw2Eth1)); | ||
131 | + | ||
132 | + String peer1Sw4Eth1 = "192.168.40.1"; | ||
133 | + peers.put(IpAddress.valueOf(peer1Sw4Eth1), | ||
134 | + new BgpPeer("00:00:00:00:00:00:00:04", 1, peer1Sw4Eth1)); | ||
135 | + | ||
136 | + expect(routingConfig.getBgpPeers()).andReturn(peers).anyTimes(); | ||
137 | + } | ||
138 | + | ||
139 | + /** | ||
140 | + * Sets up InterfaceService. | ||
141 | + */ | ||
142 | + private void setUpInterfaceService() { | ||
143 | + Set<InterfaceIpAddress> interfaceIpAddresses1 = Sets.newHashSet(); | ||
144 | + interfaceIpAddresses1.add(new InterfaceIpAddress( | ||
145 | + IpAddress.valueOf("192.168.10.101"), | ||
146 | + IpPrefix.valueOf("192.168.10.0/24"))); | ||
147 | + Interface sw1Eth1 = new Interface(SW1_ETH1, | ||
148 | + interfaceIpAddresses1, MacAddress.valueOf("00:00:00:00:00:01"), | ||
149 | + VlanId.NONE); | ||
150 | + interfaces.add(sw1Eth1); | ||
151 | + | ||
152 | + Set<InterfaceIpAddress> interfaceIpAddresses2 = Sets.newHashSet(); | ||
153 | + interfaceIpAddresses2.add( | ||
154 | + new InterfaceIpAddress(IpAddress.valueOf("192.168.20.101"), | ||
155 | + IpPrefix.valueOf("192.168.20.0/24"))); | ||
156 | + Interface sw2Eth1 = new Interface(SW2_ETH1, | ||
157 | + interfaceIpAddresses2, MacAddress.valueOf("00:00:00:00:00:02"), | ||
158 | + VlanId.NONE); | ||
159 | + interfaces.add(sw2Eth1); | ||
160 | + | ||
161 | + Set<InterfaceIpAddress> interfaceIpAddresses3 = Sets.newHashSet(); | ||
162 | + interfaceIpAddresses3.add( | ||
163 | + new InterfaceIpAddress(IpAddress.valueOf("192.168.30.101"), | ||
164 | + IpPrefix.valueOf("192.168.30.0/24"))); | ||
165 | + Interface sw3Eth1 = new Interface(SW3_ETH1, | ||
166 | + interfaceIpAddresses3, MacAddress.valueOf("00:00:00:00:00:03"), | ||
167 | + VlanId.NONE); | ||
168 | + interfaces.add(sw3Eth1); | ||
169 | + | ||
170 | + InterfaceIpAddress interfaceIpAddress4 = | ||
171 | + new InterfaceIpAddress(IpAddress.valueOf("192.168.40.101"), | ||
172 | + IpPrefix.valueOf("192.168.40.0/24")); | ||
173 | + Interface sw4Eth1 = new Interface(SW4_ETH1, | ||
174 | + Sets.newHashSet(interfaceIpAddress4), | ||
175 | + MacAddress.valueOf("00:00:00:00:00:04"), | ||
176 | + VlanId.vlanId((short) 1)); | ||
177 | + | ||
178 | + expect(interfaceService.getInterfacesByPort(SW4_ETH1)).andReturn( | ||
179 | + Collections.singleton(sw4Eth1)).anyTimes(); | ||
180 | + expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.40.1"))) | ||
181 | + .andReturn(sw4Eth1).anyTimes(); | ||
182 | + | ||
183 | + interfaces.add(sw4Eth1); | ||
184 | + | ||
185 | + expect(interfaceService.getInterfacesByPort(SW1_ETH1)).andReturn( | ||
186 | + Collections.singleton(sw1Eth1)).anyTimes(); | ||
187 | + expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.10.1"))) | ||
188 | + .andReturn(sw1Eth1).anyTimes(); | ||
189 | + expect(interfaceService.getInterfacesByPort(SW2_ETH1)).andReturn( | ||
190 | + Collections.singleton(sw2Eth1)).anyTimes(); | ||
191 | + expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.20.1"))) | ||
192 | + .andReturn(sw2Eth1).anyTimes(); | ||
193 | + expect(interfaceService.getInterfacesByPort(SW3_ETH1)).andReturn( | ||
194 | + Collections.singleton(sw3Eth1)).anyTimes(); | ||
195 | + expect(interfaceService.getMatchingInterface(Ip4Address.valueOf("192.168.30.1"))) | ||
196 | + .andReturn(sw3Eth1).anyTimes(); | ||
197 | + expect(interfaceService.getInterfaces()).andReturn(interfaces).anyTimes(); | ||
198 | + } | ||
199 | + | ||
200 | + /** | ||
201 | + * Tests adding a FIB entry to the IntentSynchronizer. | ||
202 | + * | ||
203 | + * We verify that the synchronizer records the correct state and that the | ||
204 | + * correct intent is submitted to the IntentService. | ||
205 | + */ | ||
206 | + @Test | ||
207 | + public void testFibAdd() { | ||
208 | + IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24"); | ||
209 | + FibEntry fibEntry = new FibEntry(prefix, | ||
210 | + Ip4Address.valueOf("192.168.10.1"), | ||
211 | + MacAddress.valueOf("00:00:00:00:00:01")); | ||
212 | + | ||
213 | + // Construct a MultiPointToSinglePointIntent intent | ||
214 | + TrafficSelector.Builder selectorBuilder = | ||
215 | + DefaultTrafficSelector.builder(); | ||
216 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst( | ||
217 | + fibEntry.prefix()); | ||
218 | + | ||
219 | + TrafficTreatment.Builder treatmentBuilder = | ||
220 | + DefaultTrafficTreatment.builder(); | ||
221 | + treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01")); | ||
222 | + | ||
223 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
224 | + ingressPoints.add(SW2_ETH1); | ||
225 | + ingressPoints.add(SW3_ETH1); | ||
226 | + ingressPoints.add(SW4_ETH1); | ||
227 | + | ||
228 | + MultiPointToSinglePointIntent intent = | ||
229 | + MultiPointToSinglePointIntent.builder() | ||
230 | + .appId(APPID) | ||
231 | + .key(Key.of(prefix.toString(), APPID)) | ||
232 | + .selector(selectorBuilder.build()) | ||
233 | + .treatment(treatmentBuilder.build()) | ||
234 | + .ingressPoints(ingressPoints) | ||
235 | + .egressPoint(SW1_ETH1) | ||
236 | + .constraints(SdnIpFib.CONSTRAINTS) | ||
237 | + .build(); | ||
238 | + | ||
239 | + // Setup the expected intents | ||
240 | + intentSynchronizer.submit(eqExceptId(intent)); | ||
241 | + replay(intentSynchronizer); | ||
242 | + | ||
243 | + // Send in the UPDATE FibUpdate | ||
244 | + FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry); | ||
245 | + sdnipFib.update(Collections.singleton(fibUpdate), Collections.emptyList()); | ||
246 | + | ||
247 | + verify(intentSynchronizer); | ||
248 | + } | ||
249 | + | ||
250 | + /** | ||
251 | + * Tests adding a FIB entry with to a next hop in a VLAN. | ||
252 | + * | ||
253 | + * We verify that the synchronizer records the correct state and that the | ||
254 | + * correct intent is submitted to the IntentService. | ||
255 | + */ | ||
256 | + @Test | ||
257 | + public void testFibAddWithVlan() { | ||
258 | + IpPrefix prefix = Ip4Prefix.valueOf("3.3.3.0/24"); | ||
259 | + FibEntry fibEntry = new FibEntry(prefix, | ||
260 | + Ip4Address.valueOf("192.168.40.1"), | ||
261 | + MacAddress.valueOf("00:00:00:00:00:04")); | ||
262 | + | ||
263 | + // Construct a MultiPointToSinglePointIntent intent | ||
264 | + TrafficSelector.Builder selectorBuilder = | ||
265 | + DefaultTrafficSelector.builder(); | ||
266 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV4) | ||
267 | + .matchIPDst(fibEntry.prefix()) | ||
268 | + .matchVlanId(VlanId.ANY); | ||
269 | + | ||
270 | + TrafficTreatment.Builder treatmentBuilder = | ||
271 | + DefaultTrafficTreatment.builder(); | ||
272 | + treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:04")) | ||
273 | + .setVlanId(VlanId.vlanId((short) 1)); | ||
274 | + | ||
275 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
276 | + ingressPoints.add(SW1_ETH1); | ||
277 | + ingressPoints.add(SW2_ETH1); | ||
278 | + ingressPoints.add(SW3_ETH1); | ||
279 | + | ||
280 | + MultiPointToSinglePointIntent intent = | ||
281 | + MultiPointToSinglePointIntent.builder() | ||
282 | + .appId(APPID) | ||
283 | + .key(Key.of(prefix.toString(), APPID)) | ||
284 | + .selector(selectorBuilder.build()) | ||
285 | + .treatment(treatmentBuilder.build()) | ||
286 | + .ingressPoints(ingressPoints) | ||
287 | + .egressPoint(SW4_ETH1) | ||
288 | + .constraints(SdnIpFib.CONSTRAINTS) | ||
289 | + .build(); | ||
290 | + | ||
291 | + // Setup the expected intents | ||
292 | + intentSynchronizer.submit(eqExceptId(intent)); | ||
293 | + | ||
294 | + replay(intentSynchronizer); | ||
295 | + | ||
296 | + // Send in the UPDATE FibUpdate | ||
297 | + FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, fibEntry); | ||
298 | + sdnipFib.update(Collections.singleton(fibUpdate), Collections.emptyList()); | ||
299 | + | ||
300 | + verify(intentSynchronizer); | ||
301 | + } | ||
302 | + | ||
303 | + /** | ||
304 | + * Tests updating a FIB entry. | ||
305 | + * | ||
306 | + * We verify that the synchronizer records the correct state and that the | ||
307 | + * correct intent is submitted to the IntentService. | ||
308 | + */ | ||
309 | + @Test | ||
310 | + public void testFibUpdate() { | ||
311 | + // Firstly add a route | ||
312 | + testFibAdd(); | ||
313 | + | ||
314 | + IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24"); | ||
315 | + | ||
316 | + // Start to construct a new route entry and new intent | ||
317 | + FibEntry fibEntryUpdate = new FibEntry(prefix, | ||
318 | + Ip4Address.valueOf("192.168.20.1"), | ||
319 | + MacAddress.valueOf("00:00:00:00:00:02")); | ||
320 | + | ||
321 | + // Construct a new MultiPointToSinglePointIntent intent | ||
322 | + TrafficSelector.Builder selectorBuilderNew = | ||
323 | + DefaultTrafficSelector.builder(); | ||
324 | + selectorBuilderNew.matchEthType(Ethernet.TYPE_IPV4).matchIPDst( | ||
325 | + fibEntryUpdate.prefix()); | ||
326 | + | ||
327 | + TrafficTreatment.Builder treatmentBuilderNew = | ||
328 | + DefaultTrafficTreatment.builder(); | ||
329 | + treatmentBuilderNew.setEthDst(MacAddress.valueOf("00:00:00:00:00:02")); | ||
330 | + | ||
331 | + Set<ConnectPoint> ingressPointsNew = new HashSet<>(); | ||
332 | + ingressPointsNew.add(SW1_ETH1); | ||
333 | + ingressPointsNew.add(SW3_ETH1); | ||
334 | + ingressPointsNew.add(SW4_ETH1); | ||
335 | + | ||
336 | + MultiPointToSinglePointIntent intentNew = | ||
337 | + MultiPointToSinglePointIntent.builder() | ||
338 | + .appId(APPID) | ||
339 | + .key(Key.of(prefix.toString(), APPID)) | ||
340 | + .selector(selectorBuilderNew.build()) | ||
341 | + .treatment(treatmentBuilderNew.build()) | ||
342 | + .ingressPoints(ingressPointsNew) | ||
343 | + .egressPoint(SW2_ETH1) | ||
344 | + .constraints(SdnIpFib.CONSTRAINTS) | ||
345 | + .build(); | ||
346 | + | ||
347 | + // Set up test expectation | ||
348 | + reset(intentSynchronizer); | ||
349 | + | ||
350 | + // Setup the expected intents | ||
351 | + intentSynchronizer.submit(eqExceptId(intentNew)); | ||
352 | + replay(intentSynchronizer); | ||
353 | + | ||
354 | + // Send in the UPDATE FibUpdate | ||
355 | + FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.UPDATE, | ||
356 | + fibEntryUpdate); | ||
357 | + sdnipFib.update(Collections.singletonList(fibUpdate), | ||
358 | + Collections.emptyList()); | ||
359 | + | ||
360 | + verify(intentSynchronizer); | ||
361 | + } | ||
362 | + | ||
363 | + /** | ||
364 | + * Tests deleting a FIB entry. | ||
365 | + * | ||
366 | + * We verify that the synchronizer records the correct state and that the | ||
367 | + * correct intent is withdrawn from the IntentService. | ||
368 | + */ | ||
369 | + @Test | ||
370 | + public void testFibDelete() { | ||
371 | + // Firstly add a route | ||
372 | + testFibAdd(); | ||
373 | + | ||
374 | + IpPrefix prefix = Ip4Prefix.valueOf("1.1.1.0/24"); | ||
375 | + | ||
376 | + // Construct the existing route entry | ||
377 | + FibEntry fibEntry = new FibEntry(prefix, null, null); | ||
378 | + | ||
379 | + // Construct the existing MultiPointToSinglePoint intent | ||
380 | + TrafficSelector.Builder selectorBuilder = | ||
381 | + DefaultTrafficSelector.builder(); | ||
382 | + selectorBuilder.matchEthType(Ethernet.TYPE_IPV4).matchIPDst( | ||
383 | + fibEntry.prefix()); | ||
384 | + | ||
385 | + TrafficTreatment.Builder treatmentBuilder = | ||
386 | + DefaultTrafficTreatment.builder(); | ||
387 | + treatmentBuilder.setEthDst(MacAddress.valueOf("00:00:00:00:00:01")); | ||
388 | + | ||
389 | + Set<ConnectPoint> ingressPoints = new HashSet<>(); | ||
390 | + ingressPoints.add(SW2_ETH1); | ||
391 | + ingressPoints.add(SW3_ETH1); | ||
392 | + ingressPoints.add(SW4_ETH1); | ||
393 | + | ||
394 | + MultiPointToSinglePointIntent addedIntent = | ||
395 | + MultiPointToSinglePointIntent.builder() | ||
396 | + .appId(APPID) | ||
397 | + .key(Key.of(prefix.toString(), APPID)) | ||
398 | + .selector(selectorBuilder.build()) | ||
399 | + .treatment(treatmentBuilder.build()) | ||
400 | + .ingressPoints(ingressPoints) | ||
401 | + .egressPoint(SW1_ETH1) | ||
402 | + .constraints(SdnIpFib.CONSTRAINTS) | ||
403 | + .build(); | ||
404 | + | ||
405 | + // Set up expectation | ||
406 | + reset(intentSynchronizer); | ||
407 | + // Setup the expected intents | ||
408 | + intentSynchronizer.withdraw(eqExceptId(addedIntent)); | ||
409 | + replay(intentSynchronizer); | ||
410 | + | ||
411 | + // Send in the DELETE FibUpdate | ||
412 | + FibUpdate fibUpdate = new FibUpdate(FibUpdate.Type.DELETE, fibEntry); | ||
413 | + sdnipFib.update(Collections.emptyList(), Collections.singletonList(fibUpdate)); | ||
414 | + | ||
415 | + verify(intentSynchronizer); | ||
416 | + } | ||
417 | +} |
... | @@ -17,7 +17,6 @@ package org.onosproject.sdnip; | ... | @@ -17,7 +17,6 @@ package org.onosproject.sdnip; |
17 | 17 | ||
18 | import org.easymock.IArgumentMatcher; | 18 | import org.easymock.IArgumentMatcher; |
19 | import org.onosproject.net.intent.Intent; | 19 | import org.onosproject.net.intent.Intent; |
20 | -import org.onosproject.sdnip.IntentSynchronizer.IntentKey; | ||
21 | 20 | ||
22 | import static org.easymock.EasyMock.reportMatcher; | 21 | import static org.easymock.EasyMock.reportMatcher; |
23 | 22 | ||
... | @@ -53,8 +52,6 @@ public final class TestIntentServiceHelper { | ... | @@ -53,8 +52,6 @@ public final class TestIntentServiceHelper { |
53 | * the solution is to use an EasyMock matcher that verifies that all the | 52 | * the solution is to use an EasyMock matcher that verifies that all the |
54 | * value properties of the provided intent match the expected values, but | 53 | * value properties of the provided intent match the expected values, but |
55 | * ignores the intent ID when testing equality. | 54 | * ignores the intent ID when testing equality. |
56 | - * | ||
57 | - * FIXME this currently does not take key into account | ||
58 | */ | 55 | */ |
59 | private static final class IdAgnosticIntentMatcher implements | 56 | private static final class IdAgnosticIntentMatcher implements |
60 | IArgumentMatcher { | 57 | IArgumentMatcher { |
... | @@ -86,9 +83,7 @@ public final class TestIntentServiceHelper { | ... | @@ -86,9 +83,7 @@ public final class TestIntentServiceHelper { |
86 | Intent providedIntent = (Intent) object; | 83 | Intent providedIntent = (Intent) object; |
87 | providedString = providedIntent.toString(); | 84 | providedString = providedIntent.toString(); |
88 | 85 | ||
89 | - IntentKey thisIntentKey = new IntentKey(intent); | 86 | + return IntentUtils.equals(intent, providedIntent); |
90 | - IntentKey providedIntentKey = new IntentKey(providedIntent); | ||
91 | - return thisIntentKey.equals(providedIntentKey); | ||
92 | } | 87 | } |
93 | } | 88 | } |
94 | 89 | ... | ... |
... | @@ -574,8 +574,10 @@ public class EventuallyConsistentMapImpl<K, V> | ... | @@ -574,8 +574,10 @@ public class EventuallyConsistentMapImpl<K, V> |
574 | return; | 574 | return; |
575 | } | 575 | } |
576 | try { | 576 | try { |
577 | - log.debug("Received anti-entropy advertisement from {} for {} with {} entries in it", | 577 | + if (log.isTraceEnabled()) { |
578 | + log.trace("Received anti-entropy advertisement from {} for {} with {} entries in it", | ||
578 | mapName, ad.sender(), ad.digest().size()); | 579 | mapName, ad.sender(), ad.digest().size()); |
580 | + } | ||
579 | antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners); | 581 | antiEntropyCheckLocalItems(ad).forEach(this::notifyListeners); |
580 | 582 | ||
581 | if (!lightweightAntiEntropy) { | 583 | if (!lightweightAntiEntropy) { | ... | ... |
-
Please register or login to post a comment