sangho
Committed by Pavlin Radoslavov

ONOS-973: Implemented a unit test for OpenFlowGroupProvider implmentation.

 - Fixed a bug in OpenFlowGroupProvider of wrong handling of pending group operations.

Change-Id: I70b80629f4eed000110d242f3558abe49b6b13bc
...@@ -28,7 +28,6 @@ import org.projectfloodlight.openflow.types.OFGroup; ...@@ -28,7 +28,6 @@ import org.projectfloodlight.openflow.types.OFGroup;
28 import org.slf4j.Logger; 28 import org.slf4j.Logger;
29 29
30 import java.util.concurrent.TimeUnit; 30 import java.util.concurrent.TimeUnit;
31 -import java.util.concurrent.atomic.AtomicLong;
32 31
33 import static org.slf4j.LoggerFactory.getLogger; 32 import static org.slf4j.LoggerFactory.getLogger;
34 33
...@@ -43,7 +42,6 @@ public class GroupStatsCollector implements TimerTask { ...@@ -43,7 +42,6 @@ public class GroupStatsCollector implements TimerTask {
43 private final int refreshInterval; 42 private final int refreshInterval;
44 43
45 private Timeout timeout; 44 private Timeout timeout;
46 - private final AtomicLong xidCounter = new AtomicLong(1);
47 45
48 private boolean stopTimer = false; 46 private boolean stopTimer = false;
49 47
...@@ -79,7 +77,7 @@ public class GroupStatsCollector implements TimerTask { ...@@ -79,7 +77,7 @@ public class GroupStatsCollector implements TimerTask {
79 if (sw.getRole() != RoleState.MASTER) { 77 if (sw.getRole() != RoleState.MASTER) {
80 return; 78 return;
81 } 79 }
82 - Long statsXid = xidCounter.getAndAdd(2); 80 + Long statsXid = OpenFlowGroupProvider.getXidAndAdd(2);
83 OFGroupStatsRequest statsRequest = sw.factory().buildGroupStatsRequest() 81 OFGroupStatsRequest statsRequest = sw.factory().buildGroupStatsRequest()
84 .setGroup(OFGroup.ALL) 82 .setGroup(OFGroup.ALL)
85 .setXid(statsXid) 83 .setXid(statsXid)
......
...@@ -83,12 +83,15 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -83,12 +83,15 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
83 83
84 private final InternalGroupProvider listener = new InternalGroupProvider(); 84 private final InternalGroupProvider listener = new InternalGroupProvider();
85 85
86 - private final AtomicLong xidCounter = new AtomicLong(1); 86 + private static final AtomicLong XID_COUNTER = new AtomicLong(1);
87 private final Map<Dpid, GroupStatsCollector> collectors = Maps.newHashMap(); 87 private final Map<Dpid, GroupStatsCollector> collectors = Maps.newHashMap();
88 - private final Map<Long, OFStatsReply> groupStats = Maps.newHashMap(); 88 + private final Map<Long, OFStatsReply> groupStats = Maps.newConcurrentMap();
89 - private final Map<Long, GroupOperation> pendingGroupOperations = 89 + private final Map<Integer, GroupOperation> pendingGroupOperations =
90 Maps.newConcurrentMap(); 90 Maps.newConcurrentMap();
91 91
92 + /* Map<Group ID, Transaction ID> */
93 + private final Map<Integer, Long> pendingXidMaps = Maps.newConcurrentMap();
94 +
92 /** 95 /**
93 * Creates a OpenFlow group provider. 96 * Creates a OpenFlow group provider.
94 */ 97 */
...@@ -126,10 +129,10 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -126,10 +129,10 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
126 OpenFlowSwitch sw = controller.getSwitch(dpid); 129 OpenFlowSwitch sw = controller.getSwitch(dpid);
127 for (GroupOperation groupOperation: groupOps.operations()) { 130 for (GroupOperation groupOperation: groupOps.operations()) {
128 if (sw == null) { 131 if (sw == null) {
129 - log.error("SW {} is not found", sw.getStringId()); 132 + log.error("SW {} is not found", dpid);
130 return; 133 return;
131 } 134 }
132 - final Long groupModXid = xidCounter.getAndIncrement(); 135 + final Long groupModXid = XID_COUNTER.getAndIncrement();
133 GroupModBuilder builder = 136 GroupModBuilder builder =
134 GroupModBuilder.builder(groupOperation.buckets(), 137 GroupModBuilder.builder(groupOperation.buckets(),
135 groupOperation.groupId(), 138 groupOperation.groupId(),
...@@ -151,7 +154,9 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -151,7 +154,9 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
151 log.error("Unsupported Group operation"); 154 log.error("Unsupported Group operation");
152 } 155 }
153 sw.sendMsg(groupMod); 156 sw.sendMsg(groupMod);
154 - pendingGroupOperations.put(groupModXid, groupOperation); 157 + pendingGroupOperations.put(groupMod.getGroup().getGroupNumber(),
158 + groupOperation);
159 + pendingXidMaps.put(groupMod.getGroup().getGroupNumber(), groupModXid);
155 } 160 }
156 } 161 }
157 162
...@@ -161,6 +166,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -161,6 +166,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
161 OFGroupStatsReply groupStatsReply = null; 166 OFGroupStatsReply groupStatsReply = null;
162 OFGroupDescStatsReply groupDescStatsReply = null; 167 OFGroupDescStatsReply groupDescStatsReply = null;
163 168
169 + synchronized (groupStats) {
164 if (statsReply.getStatsType() == OFStatsType.GROUP) { 170 if (statsReply.getStatsType() == OFStatsType.GROUP) {
165 OFStatsReply reply = groupStats.get(statsReply.getXid() + 1); 171 OFStatsReply reply = groupStats.get(statsReply.getXid() + 1);
166 if (reply != null) { 172 if (reply != null) {
...@@ -180,6 +186,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -180,6 +186,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
180 groupStats.put(statsReply.getXid(), statsReply); 186 groupStats.put(statsReply.getXid(), statsReply);
181 } 187 }
182 } 188 }
189 + }
183 190
184 if (groupStatsReply != null && groupDescStatsReply != null) { 191 if (groupStatsReply != null && groupDescStatsReply != null) {
185 Collection<Group> groups = buildGroupMetrics(deviceId, 192 Collection<Group> groups = buildGroupMetrics(deviceId,
...@@ -187,6 +194,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -187,6 +194,7 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
187 providerService.pushGroupMetrics(deviceId, groups); 194 providerService.pushGroupMetrics(deviceId, groups);
188 for (Group group: groups) { 195 for (Group group: groups) {
189 pendingGroupOperations.remove(group.id()); 196 pendingGroupOperations.remove(group.id());
197 + pendingXidMaps.remove(group.id());
190 } 198 }
191 } 199 }
192 } 200 }
...@@ -238,6 +246,17 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -238,6 +246,17 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
238 return null; 246 return null;
239 } 247 }
240 248
249 + /**
250 + * Returns a transaction ID for entire group operations and increases
251 + * the counter by the number given.
252 + *
253 + * @param increase the amount to increase the counter by
254 + * @return a transaction ID
255 + */
256 + public static long getXidAndAdd(int increase) {
257 + return XID_COUNTER.getAndAdd(increase);
258 + }
259 +
241 private class InternalGroupProvider 260 private class InternalGroupProvider
242 implements OpenFlowSwitchListener, OpenFlowEventListener { 261 implements OpenFlowSwitchListener, OpenFlowEventListener {
243 262
...@@ -250,11 +269,28 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv ...@@ -250,11 +269,28 @@ public class OpenFlowGroupProvider extends AbstractProvider implements GroupProv
250 case ERROR: 269 case ERROR:
251 OFErrorMsg errorMsg = (OFErrorMsg) msg; 270 OFErrorMsg errorMsg = (OFErrorMsg) msg;
252 if (errorMsg.getErrType() == OFErrorType.GROUP_MOD_FAILED) { 271 if (errorMsg.getErrType() == OFErrorType.GROUP_MOD_FAILED) {
272 + int pendingGroupId = -1;
273 + for (Map.Entry<Integer, Long> entry: pendingXidMaps.entrySet()) {
274 + if (entry.getValue() == errorMsg.getXid()) {
275 + pendingGroupId = entry.getKey();
276 + break;
277 + }
278 + }
279 + if (pendingGroupId == -1) {
280 + log.warn("Error for unknown group operation: {}",
281 + errorMsg.getXid());
282 + } else {
253 GroupOperation operation = 283 GroupOperation operation =
254 - pendingGroupOperations.get(errorMsg.getXid()); 284 + pendingGroupOperations.get(pendingGroupId);
255 if (operation != null) { 285 if (operation != null) {
256 providerService.groupOperationFailed(operation); 286 providerService.groupOperationFailed(operation);
257 - log.warn("received Error message {} from {}", msg, dpid); 287 + pendingGroupOperations.remove(pendingGroupId);
288 + pendingXidMaps.remove(pendingGroupId);
289 + log.warn("Received an group mod error {}", msg);
290 + } else {
291 + log.error("Cannot find pending group operation with group ID: {}",
292 + pendingGroupId);
293 + }
258 } 294 }
259 break; 295 break;
260 } 296 }
......
1 +package org.onosproject.provider.of.group.impl;
2 +
3 +import com.google.common.collect.Lists;
4 +import org.junit.After;
5 +import org.junit.Before;
6 +import org.junit.Test;
7 +import org.onosproject.core.DefaultGroupId;
8 +import org.onosproject.core.GroupId;
9 +import org.onosproject.net.DeviceId;
10 +import org.onosproject.net.PortNumber;
11 +import org.onosproject.net.flow.DefaultTrafficTreatment;
12 +import org.onosproject.net.flow.TrafficTreatment;
13 +import org.onosproject.net.group.DefaultGroupBucket;
14 +import org.onosproject.net.group.Group;
15 +import org.onosproject.net.group.GroupBucket;
16 +import org.onosproject.net.group.GroupBuckets;
17 +import org.onosproject.net.group.GroupDescription;
18 +import org.onosproject.net.group.GroupOperation;
19 +import org.onosproject.net.group.GroupOperations;
20 +import org.onosproject.net.group.GroupProvider;
21 +import org.onosproject.net.group.GroupProviderRegistry;
22 +import org.onosproject.net.group.GroupProviderService;
23 +import org.onosproject.net.provider.AbstractProviderService;
24 +import org.onosproject.net.provider.ProviderId;
25 +import org.onosproject.openflow.controller.Dpid;
26 +import org.onosproject.openflow.controller.OpenFlowController;
27 +import org.onosproject.openflow.controller.OpenFlowEventListener;
28 +import org.onosproject.openflow.controller.OpenFlowSwitch;
29 +import org.onosproject.openflow.controller.OpenFlowSwitchListener;
30 +import org.onosproject.openflow.controller.PacketListener;
31 +import org.onosproject.openflow.controller.RoleState;
32 +import org.projectfloodlight.openflow.protocol.OFFactories;
33 +import org.projectfloodlight.openflow.protocol.OFFactory;
34 +import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
35 +import org.projectfloodlight.openflow.protocol.OFGroupMod;
36 +import org.projectfloodlight.openflow.protocol.OFGroupModFailedCode;
37 +import org.projectfloodlight.openflow.protocol.OFGroupStatsReply;
38 +import org.projectfloodlight.openflow.protocol.OFGroupType;
39 +import org.projectfloodlight.openflow.protocol.OFMessage;
40 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
41 +import org.projectfloodlight.openflow.protocol.OFVersion;
42 +import org.projectfloodlight.openflow.protocol.errormsg.OFGroupModFailedErrorMsg;
43 +import org.projectfloodlight.openflow.types.OFGroup;
44 +
45 +import java.util.Collection;
46 +import java.util.List;
47 +import java.util.Set;
48 +
49 +import static org.junit.Assert.assertEquals;
50 +import static org.junit.Assert.assertNotNull;
51 +import static org.junit.Assert.assertNull;
52 +
53 +public class OpenFlowGroupProviderTest {
54 +
55 + OpenFlowGroupProvider provider = new OpenFlowGroupProvider();
56 + private final OpenFlowController controller = new TestController();
57 + GroupProviderRegistry providerRegistry = new TestGroupProviderRegistry();
58 + GroupProviderService providerService;
59 +
60 + private DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
61 + private Dpid dpid1 = Dpid.dpid(deviceId.uri());
62 +
63 + @Before
64 + public void setUp() {
65 + provider.controller = controller;
66 + provider.providerRegistry = providerRegistry;
67 + provider.activate();
68 + }
69 +
70 + @Test
71 + public void basics() {
72 + assertNotNull("registration expected", providerService);
73 + assertEquals("incorrect provider", provider, providerService.provider());
74 + }
75 +
76 + @Test
77 + public void addGroup() {
78 +
79 + GroupId groupId = new DefaultGroupId(1);
80 +
81 + List<GroupBucket> bucketList = Lists.newArrayList();
82 + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
83 + builder.setOutput(PortNumber.portNumber(1));
84 + GroupBucket bucket =
85 + DefaultGroupBucket.createSelectGroupBucket(builder.build());
86 + bucketList.add(bucket);
87 + GroupBuckets buckets = new GroupBuckets(bucketList);
88 +
89 + List<GroupOperation> operationList = Lists.newArrayList();
90 + GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
91 + GroupDescription.Type.SELECT, buckets);
92 + operationList.add(operation);
93 + GroupOperations operations = new GroupOperations(operationList);
94 +
95 + provider.performGroupOperation(deviceId, operations);
96 +
97 + final Dpid dpid = Dpid.dpid(deviceId.uri());
98 + TestOpenFlowSwitch sw = (TestOpenFlowSwitch) controller.getSwitch(dpid);
99 + assertNotNull("Switch should not be nul", sw);
100 + assertNotNull("OFGroupMsg should not be null", sw.msg);
101 +
102 + }
103 +
104 +
105 + @Test
106 + public void groupModFailure() {
107 + TestOpenFlowGroupProviderService testProviderService =
108 + (TestOpenFlowGroupProviderService) providerService;
109 +
110 + GroupId groupId = new DefaultGroupId(1);
111 + List<GroupBucket> bucketList = Lists.newArrayList();
112 + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder();
113 + builder.setOutput(PortNumber.portNumber(1));
114 + GroupBucket bucket =
115 + DefaultGroupBucket.createSelectGroupBucket(builder.build());
116 + bucketList.add(bucket);
117 + GroupBuckets buckets = new GroupBuckets(bucketList);
118 + List<GroupOperation> operationList = Lists.newArrayList();
119 + GroupOperation operation = GroupOperation.createAddGroupOperation(groupId,
120 + GroupDescription.Type.SELECT, buckets);
121 + operationList.add(operation);
122 + GroupOperations operations = new GroupOperations(operationList);
123 +
124 + provider.performGroupOperation(deviceId, operations);
125 +
126 + OFGroupModFailedErrorMsg.Builder errorBuilder =
127 + OFFactories.getFactory(OFVersion.OF_13).errorMsgs().buildGroupModFailedErrorMsg();
128 + OFGroupMod.Builder groupBuilder = OFFactories.getFactory(OFVersion.OF_13).buildGroupModify();
129 + groupBuilder.setGroupType(OFGroupType.ALL);
130 + groupBuilder.setGroup(OFGroup.of(1));
131 + errorBuilder.setCode(OFGroupModFailedCode.GROUP_EXISTS);
132 + errorBuilder.setXid(provider.getXidAndAdd(0) - 1);
133 +
134 + controller.processPacket(dpid1, errorBuilder.build());
135 +
136 + assertNotNull("Operation failed should not be null",
137 + testProviderService.failedOperation);
138 + }
139 +
140 +
141 + @Test
142 + public void groupStatsEvent() {
143 + TestOpenFlowGroupProviderService testProviderService =
144 + (TestOpenFlowGroupProviderService) providerService;
145 +
146 + OFGroupStatsReply.Builder rep1 =
147 + OFFactories.getFactory(OFVersion.OF_13).buildGroupStatsReply();
148 + rep1.setXid(1);
149 + controller.processPacket(dpid1, rep1.build());
150 + OFGroupDescStatsReply.Builder rep2 =
151 + OFFactories.getFactory(OFVersion.OF_13).buildGroupDescStatsReply();
152 + assertNull("group entries is not set yet", testProviderService.getGroupEntries());
153 +
154 + rep2.setXid(2);
155 + controller.processPacket(dpid1, rep2.build());
156 + assertNotNull("group entries should be set", testProviderService.getGroupEntries());
157 + }
158 +
159 +
160 +
161 + @After
162 + public void tearDown() {
163 + provider.deactivate();
164 + provider.providerRegistry = null;
165 + provider.controller = null;
166 + }
167 +
168 + private class TestOpenFlowGroupProviderService
169 + extends AbstractProviderService<GroupProvider>
170 + implements GroupProviderService {
171 +
172 + Collection<Group> groups = null;
173 + GroupOperation failedOperation = null;
174 +
175 + protected TestOpenFlowGroupProviderService(GroupProvider provider) {
176 + super(provider);
177 + }
178 +
179 + @Override
180 + public void groupOperationFailed(GroupOperation operation) {
181 + this.failedOperation = operation;
182 + }
183 +
184 + @Override
185 + public void pushGroupMetrics(DeviceId deviceId, Collection<Group> groupEntries) {
186 + this.groups = groupEntries;
187 + }
188 +
189 + public Collection<Group> getGroupEntries() {
190 + return groups;
191 + }
192 + }
193 +
194 + private class TestController implements OpenFlowController {
195 +
196 + OpenFlowEventListener eventListener = null;
197 + List<OpenFlowSwitch> switches = Lists.newArrayList();
198 +
199 + public TestController() {
200 + OpenFlowSwitch testSwitch = new TestOpenFlowSwitch();
201 + switches.add(testSwitch);
202 + }
203 +
204 + @Override
205 + public void addListener(OpenFlowSwitchListener listener) {
206 + }
207 +
208 + @Override
209 + public void removeListener(OpenFlowSwitchListener listener) {
210 +
211 + }
212 +
213 + @Override
214 + public void addPacketListener(int priority, PacketListener listener) {
215 +
216 + }
217 +
218 + @Override
219 + public void removePacketListener(PacketListener listener) {
220 +
221 + }
222 +
223 + @Override
224 + public void addEventListener(OpenFlowEventListener listener) {
225 + this.eventListener = listener;
226 + }
227 +
228 + @Override
229 + public void removeEventListener(OpenFlowEventListener listener) {
230 +
231 + }
232 +
233 + @Override
234 + public void write(Dpid dpid, OFMessage msg) {
235 +
236 + }
237 +
238 + @Override
239 + public void processPacket(Dpid dpid, OFMessage msg) {
240 + eventListener.handleMessage(dpid, msg);
241 + }
242 +
243 + @Override
244 + public void setRole(Dpid dpid, RoleState role) {
245 +
246 + }
247 +
248 + @Override
249 + public Iterable<OpenFlowSwitch> getSwitches() {
250 + return switches;
251 + }
252 +
253 + @Override
254 + public Iterable<OpenFlowSwitch> getMasterSwitches() {
255 + return null;
256 + }
257 +
258 + @Override
259 + public Iterable<OpenFlowSwitch> getEqualSwitches() {
260 + return null;
261 + }
262 +
263 + @Override
264 + public OpenFlowSwitch getSwitch(Dpid dpid) {
265 + return switches.get(0);
266 + }
267 +
268 + @Override
269 + public OpenFlowSwitch getMasterSwitch(Dpid dpid) {
270 + return null;
271 + }
272 +
273 + @Override
274 + public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
275 + return null;
276 + }
277 +
278 + }
279 +
280 + private class TestGroupProviderRegistry implements GroupProviderRegistry {
281 +
282 + @Override
283 + public GroupProviderService register(GroupProvider provider) {
284 + providerService = new TestOpenFlowGroupProviderService(provider);
285 + return providerService;
286 + }
287 +
288 + @Override
289 + public void unregister(GroupProvider provider) {
290 + }
291 +
292 + @Override
293 + public Set<ProviderId> getProviders() {
294 + return null;
295 + }
296 + }
297 +
298 + private class TestOpenFlowSwitch implements OpenFlowSwitch {
299 +
300 + OFMessage msg = null;
301 +
302 + @Override
303 + public void sendMsg(OFMessage msg) {
304 + this.msg = msg;
305 + }
306 +
307 + @Override
308 + public void sendMsg(List<OFMessage> msgs) {
309 +
310 + }
311 +
312 + @Override
313 + public void sendMsg(OFMessage msg, TableType tableType) {
314 +
315 + }
316 +
317 + @Override
318 + public void handleMessage(OFMessage fromSwitch) {
319 +
320 + }
321 +
322 + @Override
323 + public void setRole(RoleState role) {
324 +
325 + }
326 +
327 + @Override
328 + public RoleState getRole() {
329 + return null;
330 + }
331 +
332 + @Override
333 + public List<OFPortDesc> getPorts() {
334 + return null;
335 + }
336 +
337 + @Override
338 + public OFFactory factory() {
339 + return OFFactories.getFactory(OFVersion.OF_13);
340 + }
341 +
342 + @Override
343 + public String getStringId() {
344 + return null;
345 + }
346 +
347 + @Override
348 + public long getId() {
349 + return 0;
350 + }
351 +
352 + @Override
353 + public String manufacturerDescription() {
354 + return null;
355 + }
356 +
357 + @Override
358 + public String datapathDescription() {
359 + return null;
360 + }
361 +
362 + @Override
363 + public String hardwareDescription() {
364 + return null;
365 + }
366 +
367 + @Override
368 + public String softwareDescription() {
369 + return null;
370 + }
371 +
372 + @Override
373 + public String serialNumber() {
374 + return null;
375 + }
376 +
377 + @Override
378 + public boolean isConnected() {
379 + return false;
380 + }
381 +
382 + @Override
383 + public void disconnectSwitch() {
384 +
385 + }
386 +
387 + @Override
388 + public void returnRoleReply(RoleState requested, RoleState response) {
389 +
390 + }
391 +
392 + @Override
393 + public boolean isOptical() {
394 + return false;
395 + }
396 +
397 + @Override
398 + public String channelId() {
399 + return null;
400 + }
401 + }
402 +}
...\ No newline at end of file ...\ No newline at end of file