Merge branch 'master' of ssh://gerrit.onlab.us:29418/onos-next
Showing
9 changed files
with
921 additions
and
7 deletions
... | @@ -25,10 +25,10 @@ import org.slf4j.LoggerFactory; | ... | @@ -25,10 +25,10 @@ import org.slf4j.LoggerFactory; |
25 | /** | 25 | /** |
26 | * Manages the connectivity requirements between peers. | 26 | * Manages the connectivity requirements between peers. |
27 | */ | 27 | */ |
28 | -public class PeerConnectivity { | 28 | +public class PeerConnectivityManager { |
29 | 29 | ||
30 | private static final Logger log = LoggerFactory.getLogger( | 30 | private static final Logger log = LoggerFactory.getLogger( |
31 | - PeerConnectivity.class); | 31 | + PeerConnectivityManager.class); |
32 | 32 | ||
33 | // TODO these shouldn't be defined here | 33 | // TODO these shouldn't be defined here |
34 | private static final short BGP_PORT = 179; | 34 | private static final short BGP_PORT = 179; |
... | @@ -41,7 +41,7 @@ public class PeerConnectivity { | ... | @@ -41,7 +41,7 @@ public class PeerConnectivity { |
41 | // TODO this sucks. | 41 | // TODO this sucks. |
42 | private int intentId = 0; | 42 | private int intentId = 0; |
43 | 43 | ||
44 | - public PeerConnectivity(SdnIpConfigService configInfoService, | 44 | + public PeerConnectivityManager(SdnIpConfigService configInfoService, |
45 | InterfaceService interfaceService, IntentService intentService) { | 45 | InterfaceService interfaceService, IntentService intentService) { |
46 | this.configInfoService = configInfoService; | 46 | this.configInfoService = configInfoService; |
47 | this.interfaceService = interfaceService; | 47 | this.interfaceService = interfaceService; | ... | ... |
... | @@ -36,7 +36,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -36,7 +36,7 @@ public class SdnIp implements SdnIpService { |
36 | protected HostService hostService; | 36 | protected HostService hostService; |
37 | 37 | ||
38 | private SdnIpConfigReader config; | 38 | private SdnIpConfigReader config; |
39 | - private PeerConnectivity peerConnectivity; | 39 | + private PeerConnectivityManager peerConnectivity; |
40 | private Router router; | 40 | private Router router; |
41 | private BgpSessionManager bgpSessionManager; | 41 | private BgpSessionManager bgpSessionManager; |
42 | 42 | ||
... | @@ -49,7 +49,7 @@ public class SdnIp implements SdnIpService { | ... | @@ -49,7 +49,7 @@ public class SdnIp implements SdnIpService { |
49 | 49 | ||
50 | InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService); | 50 | InterfaceService interfaceService = new HostServiceBasedInterfaceService(hostService); |
51 | 51 | ||
52 | - peerConnectivity = new PeerConnectivity(config, interfaceService, intentService); | 52 | + peerConnectivity = new PeerConnectivityManager(config, interfaceService, intentService); |
53 | peerConnectivity.start(); | 53 | peerConnectivity.start(); |
54 | 54 | ||
55 | router = new Router(intentService, hostService, config, interfaceService); | 55 | router = new Router(intentService, hostService, config, interfaceService); |
... | @@ -79,4 +79,8 @@ public class SdnIp implements SdnIpService { | ... | @@ -79,4 +79,8 @@ public class SdnIp implements SdnIpService { |
79 | public Collection<RouteEntry> getRoutes() { | 79 | public Collection<RouteEntry> getRoutes() { |
80 | return router.getRoutes(); | 80 | return router.getRoutes(); |
81 | } | 81 | } |
82 | + | ||
83 | + static String dpidToUri(String dpid) { | ||
84 | + return "of:" + dpid.replace(":", ""); | ||
85 | + } | ||
82 | } | 86 | } | ... | ... |
1 | +package org.onlab.onos.sdnip; | ||
2 | + | ||
3 | +import static org.easymock.EasyMock.createMock; | ||
4 | +import static org.easymock.EasyMock.expect; | ||
5 | +import static org.easymock.EasyMock.replay; | ||
6 | +import static org.easymock.EasyMock.reportMatcher; | ||
7 | +import static org.easymock.EasyMock.reset; | ||
8 | +import static org.easymock.EasyMock.verify; | ||
9 | + | ||
10 | +import java.util.ArrayList; | ||
11 | +import java.util.Collections; | ||
12 | +import java.util.HashMap; | ||
13 | +import java.util.LinkedList; | ||
14 | +import java.util.List; | ||
15 | +import java.util.Map; | ||
16 | + | ||
17 | +import org.easymock.IArgumentMatcher; | ||
18 | +import org.junit.Before; | ||
19 | +import org.junit.Ignore; | ||
20 | +import org.junit.Test; | ||
21 | +import org.onlab.onos.net.ConnectPoint; | ||
22 | +import org.onlab.onos.net.DeviceId; | ||
23 | +import org.onlab.onos.net.PortNumber; | ||
24 | +import org.onlab.onos.net.flow.DefaultTrafficSelector; | ||
25 | +import org.onlab.onos.net.flow.DefaultTrafficTreatment; | ||
26 | +import org.onlab.onos.net.flow.TrafficSelector; | ||
27 | +import org.onlab.onos.net.flow.TrafficTreatment; | ||
28 | +import org.onlab.onos.net.intent.IntentId; | ||
29 | +import org.onlab.onos.net.intent.IntentService; | ||
30 | +import org.onlab.onos.net.intent.PointToPointIntent; | ||
31 | +import org.onlab.onos.sdnip.bgp.BgpConstants; | ||
32 | +import org.onlab.onos.sdnip.config.BgpPeer; | ||
33 | +import org.onlab.onos.sdnip.config.BgpSpeaker; | ||
34 | +import org.onlab.onos.sdnip.config.Interface; | ||
35 | +import org.onlab.onos.sdnip.config.InterfaceAddress; | ||
36 | +import org.onlab.onos.sdnip.config.SdnIpConfigService; | ||
37 | +import org.onlab.packet.Ethernet; | ||
38 | +import org.onlab.packet.IPv4; | ||
39 | +import org.onlab.packet.IpAddress; | ||
40 | +import org.onlab.packet.IpPrefix; | ||
41 | +import org.onlab.packet.MacAddress; | ||
42 | + | ||
43 | +import com.google.common.collect.Sets; | ||
44 | + | ||
45 | +/** | ||
46 | + * Unit tests for PeerConnectivityManager interface. | ||
47 | + */ | ||
48 | +public class PeerConnectivityManagerTest { | ||
49 | + | ||
50 | + private PeerConnectivityManager peerConnectivityManager; | ||
51 | + private IntentService intentService; | ||
52 | + private SdnIpConfigService configInfoService; | ||
53 | + private InterfaceService interfaceService; | ||
54 | + | ||
55 | + private Map<String, BgpSpeaker> bgpSpeakers; | ||
56 | + private Map<String, Interface> interfaces; | ||
57 | + private Map<IpAddress, BgpPeer> peers; | ||
58 | + | ||
59 | + private Map<String, BgpSpeaker> configuredBgpSpeakers; | ||
60 | + private Map<String, Interface> configuredInterfaces; | ||
61 | + private Map<IpAddress, BgpPeer> configuredPeers; | ||
62 | + private List<PointToPointIntent> intentList; | ||
63 | + | ||
64 | + private final String dpid1 = "00:00:00:00:00:00:00:01"; | ||
65 | + private final String dpid2 = "00:00:00:00:00:00:00:02"; | ||
66 | + | ||
67 | + private final DeviceId deviceId1 = | ||
68 | + DeviceId.deviceId(SdnIp.dpidToUri(dpid1)); | ||
69 | + private final DeviceId deviceId2 = | ||
70 | + DeviceId.deviceId(SdnIp.dpidToUri(dpid2)); | ||
71 | + | ||
72 | + // Interfaces connected to BGP speakers | ||
73 | + private final ConnectPoint s1Eth100 = | ||
74 | + new ConnectPoint(deviceId1, PortNumber.portNumber(100)); | ||
75 | + private final ConnectPoint s2Eth100 = | ||
76 | + new ConnectPoint(deviceId2, PortNumber.portNumber(100)); | ||
77 | + | ||
78 | + // Interfaces connected to BGP peers | ||
79 | + private final ConnectPoint s1Eth1 = | ||
80 | + new ConnectPoint(deviceId1, PortNumber.portNumber(1)); | ||
81 | + private final ConnectPoint s2Eth1 = | ||
82 | + new ConnectPoint(deviceId2, PortNumber.portNumber(1)); | ||
83 | + | ||
84 | + // We don't compare the intent ID so all expected intents can use the same ID | ||
85 | + private final IntentId testIntentId = new IntentId(0); | ||
86 | + | ||
87 | + private final TrafficTreatment noTreatment = | ||
88 | + DefaultTrafficTreatment.builder().build(); | ||
89 | + | ||
90 | + @Before | ||
91 | + public void setUp() throws Exception { | ||
92 | + bgpSpeakers = Collections.unmodifiableMap(setUpBgpSpeakers()); | ||
93 | + interfaces = Collections.unmodifiableMap(setUpInterfaces()); | ||
94 | + peers = Collections.unmodifiableMap(setUpPeers()); | ||
95 | + | ||
96 | + initPeerConnectivity(); | ||
97 | + intentList = setUpIntentList(); | ||
98 | + } | ||
99 | + | ||
100 | + /** | ||
101 | + * Sets up BGP speakers. | ||
102 | + * | ||
103 | + * @return configured BGP speakers as a map from speaker name to speaker | ||
104 | + */ | ||
105 | + private Map<String, BgpSpeaker> setUpBgpSpeakers() { | ||
106 | + | ||
107 | + configuredBgpSpeakers = new HashMap<>(); | ||
108 | + | ||
109 | + BgpSpeaker bgpSpeaker1 = new BgpSpeaker( | ||
110 | + "bgpSpeaker1", | ||
111 | + "00:00:00:00:00:00:00:01", 100, | ||
112 | + "00:00:00:00:00:01"); | ||
113 | + List<InterfaceAddress> interfaceAddresses1 = | ||
114 | + new LinkedList<InterfaceAddress>(); | ||
115 | + interfaceAddresses1.add(new InterfaceAddress(dpid1, 1, "192.168.10.101")); | ||
116 | + interfaceAddresses1.add(new InterfaceAddress(dpid2, 1, "192.168.20.101")); | ||
117 | + bgpSpeaker1.setInterfaceAddresses(interfaceAddresses1); | ||
118 | + configuredBgpSpeakers.put(bgpSpeaker1.name(), bgpSpeaker1); | ||
119 | + | ||
120 | + // BGP speaker2 is attached to the same switch port with speaker1 | ||
121 | + BgpSpeaker bgpSpeaker2 = new BgpSpeaker( | ||
122 | + "bgpSpeaker2", | ||
123 | + "00:00:00:00:00:00:00:01", 100, | ||
124 | + "00:00:00:00:00:02"); | ||
125 | + List<InterfaceAddress> interfaceAddresses2 = | ||
126 | + new LinkedList<InterfaceAddress>(); | ||
127 | + interfaceAddresses2.add(new InterfaceAddress(dpid1, 1, "192.168.10.102")); | ||
128 | + interfaceAddresses2.add(new InterfaceAddress(dpid2, 1, "192.168.20.102")); | ||
129 | + bgpSpeaker2.setInterfaceAddresses(interfaceAddresses2); | ||
130 | + configuredBgpSpeakers.put(bgpSpeaker2.name(), bgpSpeaker2); | ||
131 | + | ||
132 | + BgpSpeaker bgpSpeaker3 = new BgpSpeaker( | ||
133 | + "bgpSpeaker3", | ||
134 | + "00:00:00:00:00:00:00:02", 100, | ||
135 | + "00:00:00:00:00:03"); | ||
136 | + List<InterfaceAddress> interfaceAddresses3 = | ||
137 | + new LinkedList<InterfaceAddress>(); | ||
138 | + interfaceAddresses3.add(new InterfaceAddress(dpid1, 1, "192.168.10.103")); | ||
139 | + interfaceAddresses3.add(new InterfaceAddress(dpid2, 1, "192.168.20.103")); | ||
140 | + bgpSpeaker3.setInterfaceAddresses(interfaceAddresses3); | ||
141 | + configuredBgpSpeakers.put(bgpSpeaker3.name(), bgpSpeaker3); | ||
142 | + | ||
143 | + return configuredBgpSpeakers; | ||
144 | + } | ||
145 | + | ||
146 | + /** | ||
147 | + * Sets up logical interfaces, which emulate the configured interfaces | ||
148 | + * in SDN-IP application. | ||
149 | + * | ||
150 | + * @return configured interfaces as a MAP from Interface name to Interface | ||
151 | + */ | ||
152 | + private Map<String, Interface> setUpInterfaces() { | ||
153 | + | ||
154 | + configuredInterfaces = new HashMap<>(); | ||
155 | + | ||
156 | + String interfaceSw1Eth1 = "s1-eth1"; | ||
157 | + Interface intfsw1eth1 = new Interface(s1Eth1, | ||
158 | + Collections.singleton(IpPrefix.valueOf("192.168.10.0/24")), | ||
159 | + MacAddress.valueOf("00:00:00:00:00:01")); | ||
160 | + | ||
161 | + configuredInterfaces.put(interfaceSw1Eth1, intfsw1eth1); | ||
162 | + String interfaceSw2Eth1 = "s2-eth1"; | ||
163 | + Interface intfsw2eth1 = new Interface(s2Eth1, | ||
164 | + Collections.singleton(IpPrefix.valueOf("192.168.20.0/24")), | ||
165 | + MacAddress.valueOf("00:00:00:00:00:02")); | ||
166 | + configuredInterfaces.put(interfaceSw2Eth1, intfsw2eth1); | ||
167 | + | ||
168 | + interfaceService = createMock(InterfaceService.class); | ||
169 | + | ||
170 | + expect(interfaceService.getInterface(s1Eth1)) | ||
171 | + .andReturn(intfsw1eth1).anyTimes(); | ||
172 | + expect(interfaceService.getInterface(s2Eth1)) | ||
173 | + .andReturn(intfsw2eth1).anyTimes(); | ||
174 | + | ||
175 | + // Non-existent interface used during one of the tests | ||
176 | + expect(interfaceService.getInterface(new ConnectPoint( | ||
177 | + DeviceId.deviceId(SdnIp.dpidToUri("00:00:00:00:00:00:01:00")), | ||
178 | + PortNumber.portNumber(1)))) | ||
179 | + .andReturn(null).anyTimes(); | ||
180 | + | ||
181 | + expect(interfaceService.getInterfaces()).andReturn( | ||
182 | + Sets.newHashSet(configuredInterfaces.values())).anyTimes(); | ||
183 | + replay(interfaceService); | ||
184 | + | ||
185 | + return configuredInterfaces; | ||
186 | + } | ||
187 | + | ||
188 | + /** | ||
189 | + * Sets up BGP daemon peers. | ||
190 | + * | ||
191 | + * @return configured BGP peers as a MAP from peer IP address to BgpPeer | ||
192 | + */ | ||
193 | + private Map<IpAddress, BgpPeer> setUpPeers() { | ||
194 | + | ||
195 | + configuredPeers = new HashMap<>(); | ||
196 | + | ||
197 | + String peerSw1Eth1 = "192.168.10.1"; | ||
198 | + configuredPeers.put(IpAddress.valueOf(peerSw1Eth1), | ||
199 | + new BgpPeer(dpid1, 1, peerSw1Eth1)); | ||
200 | + | ||
201 | + // Two BGP peers are connected to switch 2 port 1. | ||
202 | + String peer1Sw2Eth1 = "192.168.20.1"; | ||
203 | + configuredPeers.put(IpAddress.valueOf(peer1Sw2Eth1), | ||
204 | + new BgpPeer(dpid2, 1, peer1Sw2Eth1)); | ||
205 | + | ||
206 | + String peer2Sw2Eth1 = "192.168.20.2"; | ||
207 | + configuredPeers.put(IpAddress.valueOf(peer2Sw2Eth1), | ||
208 | + new BgpPeer(dpid2, 1, peer2Sw2Eth1)); | ||
209 | + | ||
210 | + return configuredPeers; | ||
211 | + } | ||
212 | + | ||
213 | + /** | ||
214 | + * Sets up expected point to point intent list. | ||
215 | + * | ||
216 | + * @return point to point intent list | ||
217 | + */ | ||
218 | + private List<PointToPointIntent> setUpIntentList() { | ||
219 | + | ||
220 | + intentList = new ArrayList<PointToPointIntent>(); | ||
221 | + | ||
222 | + setUpBgpIntents(); | ||
223 | + setUpIcmpIntents(); | ||
224 | + | ||
225 | + return intentList; | ||
226 | + | ||
227 | + } | ||
228 | + | ||
229 | + /** | ||
230 | + * Constructs a BGP intent and put it into the intentList. | ||
231 | + * <p/> | ||
232 | + * The purpose of this method is too simplify the setUpBgpIntents() method, | ||
233 | + * and to make the setUpBgpIntents() easy to read. | ||
234 | + * | ||
235 | + * @param srcPrefix source IP prefix to match | ||
236 | + * @param dstPrefix destination IP prefix to match | ||
237 | + * @param srcTcpPort source TCP port to match | ||
238 | + * @param dstTcpPort destination TCP port to match | ||
239 | + * @param srcConnectPoint source connect point for PointToPointIntent | ||
240 | + * @param dstConnectPoint destination connect point for PointToPointIntent | ||
241 | + */ | ||
242 | + private void bgpPathintentConstructor(String srcPrefix, String dstPrefix, | ||
243 | + Short srcTcpPort, Short dstTcpPort, | ||
244 | + ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { | ||
245 | + | ||
246 | + TrafficSelector.Builder builder = DefaultTrafficSelector.builder() | ||
247 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
248 | + .matchIPProtocol(IPv4.PROTOCOL_TCP) | ||
249 | + .matchIPSrc(IpPrefix.valueOf(srcPrefix)) | ||
250 | + .matchIPDst(IpPrefix.valueOf(dstPrefix)); | ||
251 | + | ||
252 | + if (srcTcpPort != null) { | ||
253 | + builder.matchTcpSrc(srcTcpPort); | ||
254 | + } | ||
255 | + if (dstTcpPort != null) { | ||
256 | + builder.matchTcpDst(dstTcpPort); | ||
257 | + } | ||
258 | + | ||
259 | + PointToPointIntent intent = new PointToPointIntent( | ||
260 | + testIntentId, builder.build(), noTreatment, | ||
261 | + srcConnectPoint, dstConnectPoint); | ||
262 | + | ||
263 | + intentList.add(intent); | ||
264 | + } | ||
265 | + | ||
266 | + /** | ||
267 | + * Sets up intents for BGP paths. | ||
268 | + */ | ||
269 | + private void setUpBgpIntents() { | ||
270 | + | ||
271 | + Short bgpPort = Short.valueOf((short) BgpConstants.BGP_PORT); | ||
272 | + | ||
273 | + // Start to build intents between BGP speaker1 and BGP peer1 | ||
274 | + bgpPathintentConstructor( | ||
275 | + "192.168.10.101/32", "192.168.10.1/32", null, bgpPort, | ||
276 | + s1Eth100, s1Eth1); | ||
277 | + bgpPathintentConstructor( | ||
278 | + "192.168.10.101/32", "192.168.10.1/32", bgpPort, null, | ||
279 | + s1Eth100, s1Eth1); | ||
280 | + | ||
281 | + bgpPathintentConstructor( | ||
282 | + "192.168.10.1/32", "192.168.10.101/32", null, bgpPort, | ||
283 | + s1Eth1, s1Eth100); | ||
284 | + bgpPathintentConstructor( | ||
285 | + "192.168.10.1/32", "192.168.10.101/32", bgpPort, null, | ||
286 | + s1Eth1, s1Eth100); | ||
287 | + | ||
288 | + // Start to build intents between BGP speaker1 and BGP peer2 | ||
289 | + bgpPathintentConstructor( | ||
290 | + "192.168.20.101/32", "192.168.20.1/32", null, bgpPort, | ||
291 | + s1Eth100, s2Eth1); | ||
292 | + bgpPathintentConstructor( | ||
293 | + "192.168.20.101/32", "192.168.20.1/32", bgpPort, null, | ||
294 | + s1Eth100, s2Eth1); | ||
295 | + | ||
296 | + bgpPathintentConstructor( | ||
297 | + "192.168.20.1/32", "192.168.20.101/32", null, bgpPort, | ||
298 | + s2Eth1, s1Eth100); | ||
299 | + bgpPathintentConstructor( | ||
300 | + "192.168.20.1/32", "192.168.20.101/32", bgpPort, null, | ||
301 | + s2Eth1, s1Eth100); | ||
302 | + | ||
303 | + // Start to build intents between BGP speaker1 and BGP peer3 | ||
304 | + bgpPathintentConstructor( | ||
305 | + "192.168.20.101/32", "192.168.20.2/32", null, bgpPort, | ||
306 | + s1Eth100, s2Eth1); | ||
307 | + bgpPathintentConstructor( | ||
308 | + "192.168.20.101/32", "192.168.20.2/32", bgpPort, null, | ||
309 | + s1Eth100, s2Eth1); | ||
310 | + | ||
311 | + bgpPathintentConstructor( | ||
312 | + "192.168.20.2/32", "192.168.20.101/32", null, bgpPort, | ||
313 | + s2Eth1, s1Eth100); | ||
314 | + bgpPathintentConstructor( | ||
315 | + "192.168.20.2/32", "192.168.20.101/32", bgpPort, null, | ||
316 | + s2Eth1, s1Eth100); | ||
317 | + | ||
318 | + // | ||
319 | + // Start to build intents between BGP speaker2 and BGP peer1 | ||
320 | + bgpPathintentConstructor( | ||
321 | + "192.168.10.102/32", "192.168.10.1/32", null, bgpPort, | ||
322 | + s1Eth100, s1Eth1); | ||
323 | + bgpPathintentConstructor( | ||
324 | + "192.168.10.102/32", "192.168.10.1/32", bgpPort, null, | ||
325 | + s1Eth100, s1Eth1); | ||
326 | + | ||
327 | + bgpPathintentConstructor( | ||
328 | + "192.168.10.1/32", "192.168.10.102/32", null, bgpPort, | ||
329 | + s1Eth1, s1Eth100); | ||
330 | + bgpPathintentConstructor( | ||
331 | + "192.168.10.1/32", "192.168.10.102/32", bgpPort, null, | ||
332 | + s1Eth1, s1Eth100); | ||
333 | + // Start to build intents between BGP speaker2 and BGP peer2 | ||
334 | + bgpPathintentConstructor( | ||
335 | + "192.168.20.102/32", "192.168.20.1/32", null, bgpPort, | ||
336 | + s1Eth100, s2Eth1); | ||
337 | + bgpPathintentConstructor( | ||
338 | + "192.168.20.102/32", "192.168.20.1/32", bgpPort, null, | ||
339 | + s1Eth100, s2Eth1); | ||
340 | + | ||
341 | + bgpPathintentConstructor( | ||
342 | + "192.168.20.1/32", "192.168.20.102/32", null, bgpPort, | ||
343 | + s2Eth1, s1Eth100); | ||
344 | + bgpPathintentConstructor( | ||
345 | + "192.168.20.1/32", "192.168.20.102/32", bgpPort, null, | ||
346 | + s2Eth1, s1Eth100); | ||
347 | + | ||
348 | + // Start to build intents between BGP speaker2 and BGP peer3 | ||
349 | + bgpPathintentConstructor( | ||
350 | + "192.168.20.102/32", "192.168.20.2/32", null, bgpPort, | ||
351 | + s1Eth100, s2Eth1); | ||
352 | + bgpPathintentConstructor( | ||
353 | + "192.168.20.102/32", "192.168.20.2/32", bgpPort, null, | ||
354 | + s1Eth100, s2Eth1); | ||
355 | + | ||
356 | + bgpPathintentConstructor( | ||
357 | + "192.168.20.2/32", "192.168.20.102/32", null, bgpPort, | ||
358 | + s2Eth1, s1Eth100); | ||
359 | + bgpPathintentConstructor( | ||
360 | + "192.168.20.2/32", "192.168.20.102/32", bgpPort, null, | ||
361 | + s2Eth1, s1Eth100); | ||
362 | + | ||
363 | + // | ||
364 | + // Start to build intents between BGP speaker3 and BGP peer1 | ||
365 | + bgpPathintentConstructor( | ||
366 | + "192.168.10.103/32", "192.168.10.1/32", null, bgpPort, | ||
367 | + s2Eth100, s1Eth1); | ||
368 | + bgpPathintentConstructor( | ||
369 | + "192.168.10.103/32", "192.168.10.1/32", bgpPort, null, | ||
370 | + s2Eth100, s1Eth1); | ||
371 | + | ||
372 | + bgpPathintentConstructor( | ||
373 | + "192.168.10.1/32", "192.168.10.103/32", null, bgpPort, | ||
374 | + s1Eth1, s2Eth100); | ||
375 | + bgpPathintentConstructor( | ||
376 | + "192.168.10.1/32", "192.168.10.103/32", bgpPort, null, | ||
377 | + s1Eth1, s2Eth100); | ||
378 | + | ||
379 | + // Start to build intents between BGP speaker3 and BGP peer2 | ||
380 | + bgpPathintentConstructor( | ||
381 | + "192.168.20.103/32", "192.168.20.1/32", null, bgpPort, | ||
382 | + s2Eth100, s2Eth1); | ||
383 | + bgpPathintentConstructor( | ||
384 | + "192.168.20.103/32", "192.168.20.1/32", bgpPort, null, | ||
385 | + s2Eth100, s2Eth1); | ||
386 | + | ||
387 | + bgpPathintentConstructor( | ||
388 | + "192.168.20.1/32", "192.168.20.103/32", null, bgpPort, | ||
389 | + s2Eth1, s2Eth100); | ||
390 | + bgpPathintentConstructor( | ||
391 | + "192.168.20.1/32", "192.168.20.103/32", bgpPort, null, | ||
392 | + s2Eth1, s2Eth100); | ||
393 | + | ||
394 | + // Start to build intents between BGP speaker3 and BGP peer3 | ||
395 | + bgpPathintentConstructor( | ||
396 | + "192.168.20.103/32", "192.168.20.2/32", null, bgpPort, | ||
397 | + s2Eth100, s2Eth1); | ||
398 | + bgpPathintentConstructor( | ||
399 | + "192.168.20.103/32", "192.168.20.2/32", bgpPort, null, | ||
400 | + s2Eth100, s2Eth1); | ||
401 | + | ||
402 | + bgpPathintentConstructor( | ||
403 | + "192.168.20.2/32", "192.168.20.103/32", null, bgpPort, | ||
404 | + s2Eth1, s2Eth100); | ||
405 | + bgpPathintentConstructor( | ||
406 | + "192.168.20.2/32", "192.168.20.103/32", bgpPort, null, | ||
407 | + s2Eth1, s2Eth100); | ||
408 | + } | ||
409 | + | ||
410 | + /** | ||
411 | + * Constructs a BGP intent and put it into the intentList. | ||
412 | + * <p/> | ||
413 | + * The purpose of this method is too simplify the setUpBgpIntents() method, | ||
414 | + * and to make the setUpBgpIntents() easy to read. | ||
415 | + * | ||
416 | + * @param srcPrefix source IP prefix to match | ||
417 | + * @param dstPrefix destination IP prefix to match | ||
418 | + * @param srcConnectPoint source connect point for PointToPointIntent | ||
419 | + * @param dstConnectPoint destination connect point for PointToPointIntent | ||
420 | + */ | ||
421 | + private void icmpPathintentConstructor(String srcPrefix, String dstPrefix, | ||
422 | + ConnectPoint srcConnectPoint, ConnectPoint dstConnectPoint) { | ||
423 | + | ||
424 | + TrafficSelector selector = DefaultTrafficSelector.builder() | ||
425 | + .matchEthType(Ethernet.TYPE_IPV4) | ||
426 | + .matchIPProtocol(IPv4.PROTOCOL_ICMP) | ||
427 | + .matchIPSrc(IpPrefix.valueOf(srcPrefix)) | ||
428 | + .matchIPDst(IpPrefix.valueOf(dstPrefix)) | ||
429 | + .build(); | ||
430 | + | ||
431 | + PointToPointIntent intent = new PointToPointIntent( | ||
432 | + testIntentId, selector, noTreatment, | ||
433 | + srcConnectPoint, dstConnectPoint); | ||
434 | + | ||
435 | + intentList.add(intent); | ||
436 | + } | ||
437 | + | ||
438 | + /** | ||
439 | + * Sets up intents for ICMP paths. | ||
440 | + */ | ||
441 | + private void setUpIcmpIntents() { | ||
442 | + | ||
443 | + // Start to build intents between BGP speaker1 and BGP peer1 | ||
444 | + icmpPathintentConstructor( | ||
445 | + "192.168.10.101/32", "192.168.10.1/32", s1Eth100, s1Eth1); | ||
446 | + icmpPathintentConstructor( | ||
447 | + "192.168.10.1/32", "192.168.10.101/32", s1Eth1, s1Eth100); | ||
448 | + | ||
449 | + // Start to build intents between BGP speaker1 and BGP peer2 | ||
450 | + icmpPathintentConstructor( | ||
451 | + "192.168.20.101/32", "192.168.20.1/32", s1Eth100, s2Eth1); | ||
452 | + icmpPathintentConstructor( | ||
453 | + "192.168.20.1/32", "192.168.20.101/32", s2Eth1, s1Eth100); | ||
454 | + | ||
455 | + // Start to build intents between BGP speaker1 and BGP peer3 | ||
456 | + icmpPathintentConstructor( | ||
457 | + "192.168.20.101/32", "192.168.20.2/32", s1Eth100, s2Eth1); | ||
458 | + icmpPathintentConstructor( | ||
459 | + "192.168.20.2/32", "192.168.20.101/32", s2Eth1, s1Eth100); | ||
460 | + | ||
461 | + // | ||
462 | + // Start to build intents between BGP speaker2 and BGP peer1 | ||
463 | + icmpPathintentConstructor( | ||
464 | + "192.168.10.102/32", "192.168.10.1/32", s1Eth100, s1Eth1); | ||
465 | + icmpPathintentConstructor( | ||
466 | + "192.168.10.1/32", "192.168.10.102/32", s1Eth1, s1Eth100); | ||
467 | + | ||
468 | + // Start to build intents between BGP speaker2 and BGP peer2 | ||
469 | + icmpPathintentConstructor( | ||
470 | + "192.168.20.102/32", "192.168.20.1/32", s1Eth100, s2Eth1); | ||
471 | + icmpPathintentConstructor( | ||
472 | + "192.168.20.1/32", "192.168.20.102/32", s2Eth1, s1Eth100); | ||
473 | + | ||
474 | + // Start to build intents between BGP speaker2 and BGP peer3 | ||
475 | + icmpPathintentConstructor( | ||
476 | + "192.168.20.102/32", "192.168.20.2/32", s1Eth100, s2Eth1); | ||
477 | + icmpPathintentConstructor( | ||
478 | + "192.168.20.2/32", "192.168.20.102/32", s2Eth1, s1Eth100); | ||
479 | + | ||
480 | + // | ||
481 | + // Start to build intents between BGP speaker3 and BGP peer1 | ||
482 | + icmpPathintentConstructor( | ||
483 | + "192.168.10.103/32", "192.168.10.1/32", s2Eth100, s1Eth1); | ||
484 | + icmpPathintentConstructor( | ||
485 | + "192.168.10.1/32", "192.168.10.103/32", s1Eth1, s2Eth100); | ||
486 | + | ||
487 | + // Start to build intents between BGP speaker3 and BGP peer2 | ||
488 | + icmpPathintentConstructor( | ||
489 | + "192.168.20.103/32", "192.168.20.1/32", s2Eth100, s2Eth1); | ||
490 | + icmpPathintentConstructor( | ||
491 | + "192.168.20.1/32", "192.168.20.103/32", s2Eth1, s2Eth100); | ||
492 | + | ||
493 | + // Start to build intents between BGP speaker3 and BGP peer3 | ||
494 | + icmpPathintentConstructor( | ||
495 | + "192.168.20.103/32", "192.168.20.2/32", s2Eth100, s2Eth1); | ||
496 | + icmpPathintentConstructor( | ||
497 | + "192.168.20.2/32", "192.168.20.103/32", s2Eth1, s2Eth100); | ||
498 | + | ||
499 | + } | ||
500 | + | ||
501 | + /** | ||
502 | + * Initializes peer connectivity testing environment. | ||
503 | + */ | ||
504 | + private void initPeerConnectivity() { | ||
505 | + | ||
506 | + configInfoService = createMock(SdnIpConfigService.class); | ||
507 | + expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes(); | ||
508 | + expect(configInfoService.getBgpSpeakers()).andReturn(bgpSpeakers).anyTimes(); | ||
509 | + replay(configInfoService); | ||
510 | + | ||
511 | + intentService = createMock(IntentService.class); | ||
512 | + replay(intentService); | ||
513 | + | ||
514 | + peerConnectivityManager = new PeerConnectivityManager(configInfoService, | ||
515 | + interfaceService, intentService); | ||
516 | + } | ||
517 | + | ||
518 | + /* | ||
519 | + * EasyMock matcher that matches {@link PointToPointIntent}s but | ||
520 | + * ignores the {@link IntentId} when matching. | ||
521 | + * <p/> | ||
522 | + * The normal intent equals method tests that the intent IDs are equal, | ||
523 | + * however in these tests we can't know what the intent IDs will be in | ||
524 | + * advance, so we can't set up expected intents with the correct IDs. Thus, | ||
525 | + * the solution is to use an EasyMock matcher that verifies that all the | ||
526 | + * value properties of the provided intent match the expected values, but | ||
527 | + * ignores the intent ID when testing equality. | ||
528 | + */ | ||
529 | + private static final class IdAgnosticPointToPointIntentMatcher implements | ||
530 | + IArgumentMatcher { | ||
531 | + | ||
532 | + private final PointToPointIntent intent; | ||
533 | + private String providedIntentString; | ||
534 | + | ||
535 | + /** | ||
536 | + * Constructor taking the expected intent to match against. | ||
537 | + * | ||
538 | + * @param intent the expected intent | ||
539 | + */ | ||
540 | + public IdAgnosticPointToPointIntentMatcher(PointToPointIntent intent) { | ||
541 | + this.intent = intent; | ||
542 | + } | ||
543 | + | ||
544 | + @Override | ||
545 | + public void appendTo(StringBuffer strBuffer) { | ||
546 | + strBuffer.append("PointToPointIntentMatcher unable to match: " | ||
547 | + + providedIntentString); | ||
548 | + } | ||
549 | + | ||
550 | + @Override | ||
551 | + public boolean matches(Object object) { | ||
552 | + if (!(object instanceof PointToPointIntent)) { | ||
553 | + return false; | ||
554 | + } | ||
555 | + | ||
556 | + PointToPointIntent providedIntent = (PointToPointIntent) object; | ||
557 | + providedIntentString = providedIntent.toString(); | ||
558 | + | ||
559 | + PointToPointIntent matchIntent = | ||
560 | + new PointToPointIntent(providedIntent.id(), | ||
561 | + intent.selector(), intent.treatment(), | ||
562 | + intent.ingressPoint(), intent.egressPoint()); | ||
563 | + | ||
564 | + return matchIntent.equals(providedIntent); | ||
565 | + } | ||
566 | + } | ||
567 | + | ||
568 | + /** | ||
569 | + * Matcher method to set an expected intent to match against (ignoring the | ||
570 | + * the intent ID). | ||
571 | + * | ||
572 | + * @param intent the expected intent | ||
573 | + * @return something of type PointToPointIntent | ||
574 | + */ | ||
575 | + private static PointToPointIntent eqExceptId( | ||
576 | + PointToPointIntent intent) { | ||
577 | + reportMatcher(new IdAgnosticPointToPointIntentMatcher(intent)); | ||
578 | + return null; | ||
579 | + } | ||
580 | + | ||
581 | + /** | ||
582 | + * Tests whether peer connectivity manager can set up correct BGP and | ||
583 | + * ICMP intents according to specific configuration. | ||
584 | + * <p/> | ||
585 | + * Two tricky cases included in the configuration are: 2 peers on a same | ||
586 | + * switch port, peer on the same switch with BGPd. | ||
587 | + */ | ||
588 | + @Test | ||
589 | + public void testConnectionSetup() { | ||
590 | + | ||
591 | + reset(intentService); | ||
592 | + | ||
593 | + // Sets up the expected PointToPoint intents. | ||
594 | + for (int i = 0; i < intentList.size(); i++) { | ||
595 | + intentService.submit(eqExceptId(intentList.get(i))); | ||
596 | + } | ||
597 | + | ||
598 | + replay(intentService); | ||
599 | + | ||
600 | + // Running the interface to be tested. | ||
601 | + peerConnectivityManager.start(); | ||
602 | + | ||
603 | + verify(intentService); | ||
604 | + | ||
605 | + } | ||
606 | + | ||
607 | + /** | ||
608 | + * Tests a corner case, when there are no interfaces in the configuration. | ||
609 | + */ | ||
610 | + @Test | ||
611 | + public void testNullInterfaces() { | ||
612 | + reset(interfaceService); | ||
613 | + expect(interfaceService.getInterfaces()).andReturn( | ||
614 | + Sets.<Interface>newHashSet()).anyTimes(); | ||
615 | + expect(interfaceService.getInterface(s2Eth1)) | ||
616 | + .andReturn(null).anyTimes(); | ||
617 | + expect(interfaceService.getInterface(s1Eth1)) | ||
618 | + .andReturn(null).anyTimes(); | ||
619 | + replay(interfaceService); | ||
620 | + | ||
621 | + reset(configInfoService); | ||
622 | + expect(configInfoService.getBgpPeers()).andReturn(peers).anyTimes(); | ||
623 | + expect(configInfoService.getBgpSpeakers()).andReturn(bgpSpeakers).anyTimes(); | ||
624 | + replay(configInfoService); | ||
625 | + | ||
626 | + reset(intentService); | ||
627 | + replay(intentService); | ||
628 | + peerConnectivityManager.start(); | ||
629 | + verify(intentService); | ||
630 | + } | ||
631 | + | ||
632 | + /** | ||
633 | + * Tests a corner case, when there are no BGP peers in the configuration. | ||
634 | + */ | ||
635 | + @Test | ||
636 | + public void testNullBgpPeers() { | ||
637 | + reset(interfaceService); | ||
638 | + expect(interfaceService.getInterfaces()).andReturn( | ||
639 | + Sets.newHashSet(interfaces.values())).anyTimes(); | ||
640 | + replay(interfaceService); | ||
641 | + | ||
642 | + reset(configInfoService); | ||
643 | + expect(configInfoService.getBgpPeers()).andReturn( | ||
644 | + new HashMap<IpAddress, BgpPeer>()).anyTimes(); | ||
645 | + expect(configInfoService.getBgpSpeakers()).andReturn( | ||
646 | + bgpSpeakers).anyTimes(); | ||
647 | + replay(configInfoService); | ||
648 | + | ||
649 | + reset(intentService); | ||
650 | + replay(intentService); | ||
651 | + peerConnectivityManager.start(); | ||
652 | + verify(intentService); | ||
653 | + } | ||
654 | + | ||
655 | + /** | ||
656 | + * Tests a corner case, when there is no BGP speakers in the configuration. | ||
657 | + */ | ||
658 | + @Test | ||
659 | + public void testNullBgpSpeakers() { | ||
660 | + reset(interfaceService); | ||
661 | + expect(interfaceService.getInterfaces()).andReturn( | ||
662 | + Sets.newHashSet(interfaces.values())).anyTimes(); | ||
663 | + replay(interfaceService); | ||
664 | + | ||
665 | + reset(configInfoService); | ||
666 | + expect(configInfoService.getBgpPeers()).andReturn( | ||
667 | + peers).anyTimes(); | ||
668 | + expect(configInfoService.getBgpSpeakers()).andReturn( | ||
669 | + null).anyTimes(); | ||
670 | + replay(configInfoService); | ||
671 | + | ||
672 | + reset(intentService); | ||
673 | + replay(intentService); | ||
674 | + peerConnectivityManager.start(); | ||
675 | + verify(intentService); | ||
676 | + } | ||
677 | + | ||
678 | + /** | ||
679 | + * Tests a corner case, when there is no Interface configured for one BGP | ||
680 | + * peer. | ||
681 | + */ | ||
682 | + @Test | ||
683 | + public void testNoPeerInterface() { | ||
684 | + String peerSw100Eth1 = "192.168.200.1"; | ||
685 | + configuredPeers.put(IpAddress.valueOf(peerSw100Eth1), | ||
686 | + new BgpPeer("00:00:00:00:00:00:01:00", 1, peerSw100Eth1)); | ||
687 | + testConnectionSetup(); | ||
688 | + } | ||
689 | + | ||
690 | + /** | ||
691 | + * Tests a corner case, when there is no Interface configured for one BGP | ||
692 | + * speaker. | ||
693 | + * TODO: we should add a configuration correctness checking module/method | ||
694 | + * before testing this corner case. | ||
695 | + */ | ||
696 | + @Ignore | ||
697 | + @Test | ||
698 | + public void testNoSpeakerInterface() { | ||
699 | + BgpSpeaker bgpSpeaker100 = new BgpSpeaker( | ||
700 | + "bgpSpeaker100", | ||
701 | + "00:00:00:00:00:00:01:00", 100, | ||
702 | + "00:00:00:00:01:00"); | ||
703 | + List<InterfaceAddress> interfaceAddresses100 = | ||
704 | + new LinkedList<InterfaceAddress>(); | ||
705 | + interfaceAddresses100.add(new InterfaceAddress(dpid1, 1, "192.168.10.201")); | ||
706 | + interfaceAddresses100.add(new InterfaceAddress(dpid2, 1, "192.168.20.201")); | ||
707 | + bgpSpeaker100.setInterfaceAddresses(interfaceAddresses100); | ||
708 | + configuredBgpSpeakers.put(bgpSpeaker100.name(), bgpSpeaker100); | ||
709 | + testConnectionSetup(); | ||
710 | + } | ||
711 | +} |
... | @@ -7,6 +7,8 @@ import org.onlab.onos.net.Provided; | ... | @@ -7,6 +7,8 @@ import org.onlab.onos.net.Provided; |
7 | */ | 7 | */ |
8 | public interface Topology extends Provided { | 8 | public interface Topology extends Provided { |
9 | 9 | ||
10 | + // FIXME: Following is not true right now. It is actually System.nanoTime(), | ||
11 | + // which has no relation to epoch time, wall clock, etc. | ||
10 | /** | 12 | /** |
11 | * Returns the time, specified in milliseconds since start of epoch, | 13 | * Returns the time, specified in milliseconds since start of epoch, |
12 | * when the topology became active and made available. | 14 | * when the topology became active and made available. | ... | ... |
... | @@ -52,6 +52,12 @@ | ... | @@ -52,6 +52,12 @@ |
52 | <artifactId>easymock</artifactId> | 52 | <artifactId>easymock</artifactId> |
53 | <scope>test</scope> | 53 | <scope>test</scope> |
54 | </dependency> | 54 | </dependency> |
55 | + <dependency> | ||
56 | + <groupId>org.onlab.onos</groupId> | ||
57 | + <artifactId>onos-api</artifactId> | ||
58 | + <classifier>tests</classifier> | ||
59 | + <scope>test</scope> | ||
60 | + </dependency> | ||
55 | </dependencies> | 61 | </dependencies> |
56 | 62 | ||
57 | </project> | 63 | </project> | ... | ... |
... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.flow; | ... | @@ -3,7 +3,7 @@ package org.onlab.onos.store.flow; |
3 | import org.onlab.onos.net.DeviceId; | 3 | import org.onlab.onos.net.DeviceId; |
4 | 4 | ||
5 | /** | 5 | /** |
6 | - * Service to return where the Replica should be placed. | 6 | + * Service to return where the replica should be placed. |
7 | */ | 7 | */ |
8 | public interface ReplicaInfoService { | 8 | public interface ReplicaInfoService { |
9 | 9 | ||
... | @@ -15,4 +15,19 @@ public interface ReplicaInfoService { | ... | @@ -15,4 +15,19 @@ public interface ReplicaInfoService { |
15 | * @return placement information | 15 | * @return placement information |
16 | */ | 16 | */ |
17 | ReplicaInfo getReplicaInfoFor(DeviceId deviceId); | 17 | ReplicaInfo getReplicaInfoFor(DeviceId deviceId); |
18 | + | ||
19 | + /** | ||
20 | + * Adds the specified replica placement info change listener. | ||
21 | + * | ||
22 | + * @param listener the replica placement info change listener | ||
23 | + */ | ||
24 | + void addListener(ReplicaInfoEventListener listener); | ||
25 | + | ||
26 | + /** | ||
27 | + * Removes the specified replica placement info change listener. | ||
28 | + * | ||
29 | + * @param listener the replica placement info change listener | ||
30 | + */ | ||
31 | + void removeListener(ReplicaInfoEventListener listener); | ||
32 | + | ||
18 | } | 33 | } | ... | ... |
1 | package org.onlab.onos.store.flow.impl; | 1 | package org.onlab.onos.store.flow.impl; |
2 | 2 | ||
3 | +import static com.google.common.base.Preconditions.checkNotNull; | ||
3 | import static org.slf4j.LoggerFactory.getLogger; | 4 | import static org.slf4j.LoggerFactory.getLogger; |
4 | import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED; | 5 | import static org.onlab.onos.store.flow.ReplicaInfoEvent.Type.MASTER_CHANGED; |
5 | 6 | ||
... | @@ -66,6 +67,16 @@ public class ReplicaInfoManager implements ReplicaInfoService { | ... | @@ -66,6 +67,16 @@ public class ReplicaInfoManager implements ReplicaInfoService { |
66 | Collections.<NodeId>emptyList()); | 67 | Collections.<NodeId>emptyList()); |
67 | } | 68 | } |
68 | 69 | ||
70 | + @Override | ||
71 | + public void addListener(ReplicaInfoEventListener listener) { | ||
72 | + listenerRegistry.addListener(checkNotNull(listener)); | ||
73 | + } | ||
74 | + | ||
75 | + @Override | ||
76 | + public void removeListener(ReplicaInfoEventListener listener) { | ||
77 | + listenerRegistry.removeListener(checkNotNull(listener)); | ||
78 | + } | ||
79 | + | ||
69 | final class InternalMastershipListener implements MastershipListener { | 80 | final class InternalMastershipListener implements MastershipListener { |
70 | 81 | ||
71 | @Override | 82 | @Override | ... | ... |
1 | +package org.onlab.onos.store.flow.impl; | ||
2 | + | ||
3 | +import static com.google.common.base.Preconditions.checkState; | ||
4 | +import static org.junit.Assert.*; | ||
5 | + | ||
6 | +import java.util.Collections; | ||
7 | +import java.util.Map; | ||
8 | +import java.util.concurrent.CountDownLatch; | ||
9 | +import java.util.concurrent.TimeUnit; | ||
10 | + | ||
11 | +import org.junit.After; | ||
12 | +import org.junit.Before; | ||
13 | +import org.junit.Test; | ||
14 | +import org.onlab.onos.cluster.NodeId; | ||
15 | +import org.onlab.onos.event.AbstractListenerRegistry; | ||
16 | +import org.onlab.onos.event.DefaultEventSinkRegistry; | ||
17 | +import org.onlab.onos.event.Event; | ||
18 | +import org.onlab.onos.event.EventDeliveryService; | ||
19 | +import org.onlab.onos.event.EventSink; | ||
20 | +import org.onlab.onos.mastership.MastershipEvent; | ||
21 | +import org.onlab.onos.mastership.MastershipEvent.Type; | ||
22 | +import org.onlab.onos.mastership.MastershipListener; | ||
23 | +import org.onlab.onos.mastership.MastershipService; | ||
24 | +import org.onlab.onos.mastership.MastershipServiceAdapter; | ||
25 | +import org.onlab.onos.net.DeviceId; | ||
26 | +import org.onlab.onos.store.flow.ReplicaInfo; | ||
27 | +import org.onlab.onos.store.flow.ReplicaInfoEvent; | ||
28 | +import org.onlab.onos.store.flow.ReplicaInfoEventListener; | ||
29 | +import org.onlab.onos.store.flow.ReplicaInfoService; | ||
30 | + | ||
31 | +import com.google.common.base.Optional; | ||
32 | +import com.google.common.collect.Maps; | ||
33 | + | ||
34 | +public class ReplicaInfoManagerTest { | ||
35 | + | ||
36 | + | ||
37 | + private static final DeviceId DID1 = DeviceId.deviceId("of:1"); | ||
38 | + private static final DeviceId DID2 = DeviceId.deviceId("of:2"); | ||
39 | + private static final NodeId NID1 = new NodeId("foo"); | ||
40 | + | ||
41 | + private ReplicaInfoManager mgr; | ||
42 | + private ReplicaInfoService service; | ||
43 | + | ||
44 | + private AbstractListenerRegistry<MastershipEvent, MastershipListener> | ||
45 | + mastershipListenerRegistry; | ||
46 | + private TestEventDispatcher eventDispatcher; | ||
47 | + | ||
48 | + | ||
49 | + @Before | ||
50 | + public void setUp() throws Exception { | ||
51 | + mastershipListenerRegistry = new AbstractListenerRegistry<>(); | ||
52 | + | ||
53 | + mgr = new ReplicaInfoManager(); | ||
54 | + service = mgr; | ||
55 | + | ||
56 | + eventDispatcher = new TestEventDispatcher(); | ||
57 | + mgr.eventDispatcher = eventDispatcher; | ||
58 | + mgr.mastershipService = new TestMastershipService(); | ||
59 | + | ||
60 | + // register dummy mastership event source | ||
61 | + mgr.eventDispatcher.addSink(MastershipEvent.class, mastershipListenerRegistry); | ||
62 | + | ||
63 | + mgr.activate(); | ||
64 | + } | ||
65 | + | ||
66 | + @After | ||
67 | + public void tearDown() throws Exception { | ||
68 | + mgr.deactivate(); | ||
69 | + } | ||
70 | + | ||
71 | + @Test | ||
72 | + public void testGetReplicaInfoFor() { | ||
73 | + ReplicaInfo info1 = service.getReplicaInfoFor(DID1); | ||
74 | + assertEquals(Optional.of(NID1), info1.master()); | ||
75 | + // backups are always empty for now | ||
76 | + assertEquals(Collections.emptyList(), info1.backups()); | ||
77 | + | ||
78 | + ReplicaInfo info2 = service.getReplicaInfoFor(DID2); | ||
79 | + assertEquals("There's no master", Optional.absent(), info2.master()); | ||
80 | + // backups are always empty for now | ||
81 | + assertEquals(Collections.emptyList(), info2.backups()); | ||
82 | + } | ||
83 | + | ||
84 | + @Test | ||
85 | + public void testReplicaInfoEvent() throws InterruptedException { | ||
86 | + final CountDownLatch latch = new CountDownLatch(1); | ||
87 | + service.addListener(new MasterNodeCheck(latch, DID1, NID1)); | ||
88 | + | ||
89 | + // fake MastershipEvent | ||
90 | + eventDispatcher.post(new MastershipEvent(Type.MASTER_CHANGED, DID1, NID1)); | ||
91 | + | ||
92 | + assertTrue(latch.await(1, TimeUnit.SECONDS)); | ||
93 | + } | ||
94 | + | ||
95 | + | ||
96 | + private final class MasterNodeCheck implements ReplicaInfoEventListener { | ||
97 | + private final CountDownLatch latch; | ||
98 | + private Optional<NodeId> expectedMaster; | ||
99 | + private DeviceId expectedDevice; | ||
100 | + | ||
101 | + | ||
102 | + MasterNodeCheck(CountDownLatch latch, DeviceId did, | ||
103 | + NodeId nid) { | ||
104 | + this.latch = latch; | ||
105 | + this.expectedMaster = Optional.fromNullable(nid); | ||
106 | + this.expectedDevice = did; | ||
107 | + } | ||
108 | + | ||
109 | + @Override | ||
110 | + public void event(ReplicaInfoEvent event) { | ||
111 | + assertEquals(expectedDevice, event.subject()); | ||
112 | + assertEquals(expectedMaster, event.replicaInfo().master()); | ||
113 | + // backups are always empty for now | ||
114 | + assertEquals(Collections.emptyList(), event.replicaInfo().backups()); | ||
115 | + latch.countDown(); | ||
116 | + } | ||
117 | + } | ||
118 | + | ||
119 | + | ||
120 | + private final class TestMastershipService | ||
121 | + extends MastershipServiceAdapter | ||
122 | + implements MastershipService { | ||
123 | + | ||
124 | + private Map<DeviceId, NodeId> masters; | ||
125 | + | ||
126 | + TestMastershipService() { | ||
127 | + masters = Maps.newHashMap(); | ||
128 | + masters.put(DID1, NID1); | ||
129 | + // DID2 has no master | ||
130 | + } | ||
131 | + | ||
132 | + @Override | ||
133 | + public NodeId getMasterFor(DeviceId deviceId) { | ||
134 | + return masters.get(deviceId); | ||
135 | + } | ||
136 | + | ||
137 | + @Override | ||
138 | + public void addListener(MastershipListener listener) { | ||
139 | + mastershipListenerRegistry.addListener(listener); | ||
140 | + } | ||
141 | + | ||
142 | + @Override | ||
143 | + public void removeListener(MastershipListener listener) { | ||
144 | + mastershipListenerRegistry.removeListener(listener); | ||
145 | + } | ||
146 | + } | ||
147 | + | ||
148 | + | ||
149 | + // code clone | ||
150 | + /** | ||
151 | + * Implements event delivery system that delivers events synchronously, or | ||
152 | + * in-line with the post method invocation. | ||
153 | + */ | ||
154 | + private static class TestEventDispatcher extends DefaultEventSinkRegistry | ||
155 | + implements EventDeliveryService { | ||
156 | + | ||
157 | + @SuppressWarnings({ "rawtypes", "unchecked" }) | ||
158 | + @Override | ||
159 | + public void post(Event event) { | ||
160 | + EventSink sink = getSink(event.getClass()); | ||
161 | + checkState(sink != null, "No sink for event %s", event); | ||
162 | + sink.process(event); | ||
163 | + } | ||
164 | + } | ||
165 | +} |
... | @@ -172,7 +172,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr | ... | @@ -172,7 +172,7 @@ public class OpenFlowDeviceProvider extends AbstractProvider implements DevicePr |
172 | */ | 172 | */ |
173 | private List<PortDescription> buildPortDescriptions( | 173 | private List<PortDescription> buildPortDescriptions( |
174 | List<OFPortDesc> ports) { | 174 | List<OFPortDesc> ports) { |
175 | - final List<PortDescription> portDescs = new ArrayList<>(); | 175 | + final List<PortDescription> portDescs = new ArrayList<>(ports.size()); |
176 | for (OFPortDesc port : ports) { | 176 | for (OFPortDesc port : ports) { |
177 | portDescs.add(buildPortDescription(port)); | 177 | portDescs.add(buildPortDescription(port)); |
178 | } | 178 | } | ... | ... |
-
Please register or login to post a comment