Jonathan Hart
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 1785 additions and 1521 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 +}
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,794 +148,118 @@ public class IntentSynchronizer implements FibListener, IntentRequestListener { ...@@ -187,794 +148,118 @@ 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) { 157 + intentService.submit(intent);
270 - log.trace("SDN-IP Submitting intents: {}", intent);
271 - intentService.submit(intent);
272 - }
273 } 158 }
274 } 159 }
275 } 160 }
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 -
338 - // Match the destination IP prefix at the first hop
339 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
340 - if (prefix.isIp4()) {
341 - selector.matchEthType(Ethernet.TYPE_IPV4);
342 - selector.matchIPDst(prefix);
343 - } else {
344 - selector.matchEthType(Ethernet.TYPE_IPV6);
345 - selector.matchIPv6Dst(prefix);
346 - }
347 -
348 - // Rewrite the destination MAC address
349 - TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder()
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 - }
357 -
358 - int priority =
359 - prefix.prefixLength() * PRIORITY_MULTIPLIER + PRIORITY_OFFSET;
360 - Key key = Key.of(prefix.toString(), appId);
361 - return MultiPointToSinglePointIntent.builder()
362 - .appId(appId)
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 - }
372 -
373 - @Override
374 - public void setUpConnectivityInternetToHost(IpAddress hostIpAddress) {
375 - checkNotNull(hostIpAddress);
376 - Set<ConnectPoint> ingressPoints =
377 - configService.getBgpPeerConnectPoints();
378 -
379 - TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
380 -
381 - if (hostIpAddress.isIp4()) {
382 - selector.matchEthType(Ethernet.TYPE_IPV4);
383 - } else {
384 - selector.matchEthType(Ethernet.TYPE_IPV6);
385 - }
386 180
387 - // Match the destination IP prefix at the first hop 181 + if (!isLeader) {
388 - IpPrefix ipPrefix = hostIpAddress.toIpPrefix(); 182 + this.isElectedLeader = false;
389 - selector.matchIPDst(ipPrefix); 183 + this.isActivatedLeader = false;
390 - 184 + return; // Nothing to do
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 } 185 }
186 + this.isActivatedLeader = false;
187 + this.isElectedLeader = true;
405 188
406 - TrafficTreatment.Builder treatment = 189 + // Run the synchronization method off-thread
407 - DefaultTrafficTreatment.builder().setEthDst(hostMac); 190 + bgpIntentsSynchronizerExecutor.execute(this::synchronizeIntents);
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 } 191 }
492 192
493 - /** 193 + private void synchronizeIntents() {
494 - * Synchronize the in-memory Intents with the Intents in the Intent 194 + Map<Key, Intent> serviceIntents = new HashMap<>();
495 - * framework. 195 + intentService.getIntents().forEach(i -> {
496 - */ 196 + if (i.appId().equals(appId)) {
497 - void synchronizeIntents() { 197 + serviceIntents.put(i.key(), i);
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 - }
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 - }
515 - for (Intent intent : peerIntents.values()) {
516 - localIntents.put(new IntentKey(intent), intent);
517 } 198 }
199 + });
518 200
519 - // Fetch all intents for this application 201 + List<Intent> intentsToAdd = new LinkedList<>();
520 - for (Intent intent : intentService.getIntents()) { 202 + List<Intent> intentsToRemove = new LinkedList<>();
521 - if (!intent.appId().equals(appId)) {
522 - continue;
523 - }
524 - fetchedIntents.put(new IntentKey(intent), intent);
525 - }
526 - if (log.isDebugEnabled()) {
527 - for (Intent intent: fetchedIntents.values()) {
528 - log.trace("SDN-IP Intent Synchronizer: fetched intent: {}",
529 - intent);
530 - }
531 - }
532 -
533 - computeIntentsDelta(localIntents, fetchedIntents,
534 - storeInMemoryIntents, addIntents,
535 - deleteIntents);
536 203
537 - // 204 + for (Intent localIntent : intents.values()) {
538 - // Perform the actions: 205 + Intent serviceIntent = serviceIntents.remove(localIntent.key());
539 - // 1. Store in memory fetched intents that are same. Can be done 206 + if (serviceIntent == null) {
540 - // even if we are not the leader anymore 207 + intentsToAdd.add(localIntent);
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 -
582 - // Withdraw Intents
583 - for (Intent intent : deleteIntents) {
584 - intentService.withdraw(intent);
585 - log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}",
586 - intent);
587 - }
588 - if (!isElectedLeader) {
589 - log.trace("SDN-IP Intent Synchronizer: cannot withdraw intents: " +
590 - "not elected leader anymore");
591 - isActivatedLeader = false;
592 - return;
593 - }
594 -
595 - // Add Intents
596 - for (Intent intent : addIntents) {
597 - intentService.submit(intent);
598 - log.trace("SDN-IP Intent Synchronizer: submitting intent: {}",
599 - intent);
600 - }
601 - if (!isElectedLeader) {
602 - log.trace("SDN-IP Intent Synchronizer: cannot submit intents: " +
603 - "not elected leader anymore");
604 - isActivatedLeader = false;
605 - return;
606 - }
607 -
608 - if (isElectedLeader) {
609 - isActivatedLeader = true; // Allow push of Intents
610 } else { 208 } else {
611 - isActivatedLeader = false; 209 + IntentState state = intentService.getIntentState(serviceIntent.key());
612 - } 210 + if (!IntentUtils.equals(serviceIntent, localIntent) || state == null ||
613 - log.debug("SDN-IP intent synchronization completed"); 211 + state == IntentState.WITHDRAW_REQ ||
614 - } 212 + state == IntentState.WITHDRAWING ||
615 - } 213 + state == IntentState.WITHDRAWN) {
616 - 214 + intentsToAdd.add(localIntent);
617 - /** 215 + }
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 } 216 }
677 - storeInMemoryIntents.add(fetchedIntent);
678 } 217 }
679 218
680 - for (Map.Entry<IntentKey, Intent> entry : fetchedIntents.entrySet()) { 219 + for (Intent serviceIntent : serviceIntents.values()) {
681 - IntentKey intentKey = entry.getKey(); 220 + IntentState state = intentService.getIntentState(serviceIntent.key());
682 - Intent fetchedIntent = entry.getValue(); 221 + if (state != null && state != IntentState.WITHDRAW_REQ
683 - Intent localIntent = localIntents.get(intentKey); 222 + && state != IntentState.WITHDRAWING
684 - 223 + && state != IntentState.WITHDRAWN) {
685 - if (localIntent != null) { 224 + intentsToRemove.add(serviceIntent);
686 - continue;
687 } 225 }
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 } 226 }
722 227
723 - /** 228 + log.debug("SDN-IP Intent Synchronizer: submitting {}, withdrawing {}",
724 - * Compares two Multi-Point to Single-Point Intents whether they 229 + intentsToAdd.size(), intentsToRemove.size());
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 230
741 - /** 231 + // Withdraw Intents
742 - * Compares two Point-to-Point Intents whether they represent 232 + for (Intent intent : intentsToRemove) {
743 - * same logical intention. 233 + intentService.withdraw(intent);
744 - * 234 + log.trace("SDN-IP Intent Synchronizer: withdrawing intent: {}",
745 - * @param intent1 the first Intent to compare 235 + intent);
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 } 236 }
758 - 237 + if (!isElectedLeader) {
759 - @Override 238 + log.debug("SDN-IP Intent Synchronizer: cannot withdraw intents: " +
760 - public int hashCode() { 239 + "not elected leader anymore");
761 - if (intent instanceof PointToPointIntent) { 240 + isActivatedLeader = false;
762 - PointToPointIntent p2pIntent = (PointToPointIntent) intent; 241 + return;
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 } 242 }
814 - }
815 243
816 - @Override 244 + // Add Intents
817 - public void setUpConnectivityHostToHost(IpAddress dstIpAddress, 245 + for (Intent intent : intentsToAdd) {
818 - IpAddress srcIpAddress, 246 + intentService.submit(intent);
819 - MacAddress srcMacAddress, 247 + log.trace("SDN-IP Intent Synchronizer: submitting intent: {}",
820 - ConnectPoint srcConnectPoint) { 248 + intent);
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 } 249 }
838 - if (dstMacAddress == null) { 250 + if (!isElectedLeader) {
839 - hostService.startMonitoringIp(dstIpAddress); 251 + log.debug("SDN-IP Intent Synchronizer: cannot submit intents: " +
252 + "not elected leader anymore");
253 + isActivatedLeader = false;
840 return; 254 return;
841 } 255 }
842 256
843 - // 257 + if (isElectedLeader) {
844 - // Handle intent from source host to destination host 258 + isActivatedLeader = true; // Allow push of Intents
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 { 259 } else {
862 - // There is no existing intent, create a new one. 260 + isActivatedLeader = false;
863 - MultiPointToSinglePointIntent dstToSrcIntent =
864 - hostToHostIntentGenerator(srcIpAddress, srcConnectPoint,
865 - srcMacAddress, dstConnectPoint);
866 - submitReactiveIntent(srcIpPrefix, dstToSrcIntent);
867 } 261 }
262 + log.debug("SDN-IP intent synchronization completed");
868 } 263 }
869 264
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 }
...@@ -646,7 +404,7 @@ public class IntentSyncTest extends AbstractIntentTest { ...@@ -646,7 +404,7 @@ public class IntentSyncTest extends AbstractIntentTest {
646 * @return the newly constructed MultiPointToSinglePointIntent 404 * @return the newly constructed MultiPointToSinglePointIntent
647 * @throws TestUtilsException 405 * @throws TestUtilsException
648 */ 406 */
649 - private MultiPointToSinglePointIntent staticIntentBuilder( 407 + private MultiPointToSinglePointIntent staticIntentBuilder(
650 MultiPointToSinglePointIntent intent, RouteEntry routeEntry, 408 MultiPointToSinglePointIntent intent, RouteEntry routeEntry,
651 String nextHopMacAddress) throws TestUtilsException { 409 String nextHopMacAddress) throws TestUtilsException {
652 410
......
...@@ -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
......
...@@ -521,7 +521,7 @@ public class EventuallyConsistentMapImpl<K, V> ...@@ -521,7 +521,7 @@ public class EventuallyConsistentMapImpl<K, V>
521 return; 521 return;
522 } 522 }
523 peers.forEach(node -> 523 peers.forEach(node ->
524 - senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event) 524 + senderPending.computeIfAbsent(node, unusedKey -> new EventAccumulator(node)).add(event)
525 ); 525 );
526 } 526 }
527 527
...@@ -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 - mapName, ad.sender(), ad.digest().size()); 578 + log.trace("Received anti-entropy advertisement from {} for {} with {} entries in it",
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) {
......