Ayaka Koshibe

refactored RoleManager to handle multiple pending requests

Change-Id: I669e0527107c5bd29c1600f4667424bc4e6f6b7e
...@@ -300,7 +300,6 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver { ...@@ -300,7 +300,6 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitchDriver {
300 this.transitionToEqualSwitch(); 300 this.transitionToEqualSwitch();
301 } 301 }
302 } else { 302 } else {
303 - log.warn(">>> mismatch with expected role - got {} - Disconnecting", r);
304 this.disconnectSwitch(); 303 this.disconnectSwitch();
305 } 304 }
306 } 305 }
......
...@@ -17,6 +17,7 @@ package org.onlab.onos.openflow.controller.impl; ...@@ -17,6 +17,7 @@ package org.onlab.onos.openflow.controller.impl;
17 17
18 import java.io.IOException; 18 import java.io.IOException;
19 import java.util.Collections; 19 import java.util.Collections;
20 +import java.util.concurrent.TimeUnit;
20 21
21 import org.onlab.onos.openflow.controller.RoleState; 22 import org.onlab.onos.openflow.controller.RoleState;
22 import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver; 23 import org.onlab.onos.openflow.controller.driver.OpenFlowSwitchDriver;
...@@ -41,6 +42,9 @@ import org.projectfloodlight.openflow.types.U64; ...@@ -41,6 +42,9 @@ import org.projectfloodlight.openflow.types.U64;
41 import org.slf4j.Logger; 42 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory; 43 import org.slf4j.LoggerFactory;
43 44
45 +import com.google.common.cache.Cache;
46 +import com.google.common.cache.CacheBuilder;
47 +
44 48
45 /** 49 /**
46 * A utility class to handle role requests and replies for this channel. 50 * A utility class to handle role requests and replies for this channel.
...@@ -59,13 +63,15 @@ class RoleManager implements RoleHandler { ...@@ -59,13 +63,15 @@ class RoleManager implements RoleHandler {
59 protected static final long NICIRA_EXPERIMENTER = 0x2320; 63 protected static final long NICIRA_EXPERIMENTER = 0x2320;
60 64
61 private static Logger log = LoggerFactory.getLogger(RoleManager.class); 65 private static Logger log = LoggerFactory.getLogger(RoleManager.class);
62 - // indicates that a request is currently pending 66 +
63 - // needs to be volatile to allow correct double-check idiom 67 + // The time until cached XID is evicted. Arbitray for now.
64 - private volatile boolean requestPending; 68 + private final int pendingXidTimeoutSeconds = 60;
65 - // the transaction Id of the pending request 69 +
66 - private int pendingXid; 70 + // The cache for pending expected RoleReplies keyed on expected XID
67 - // the role that's pending 71 + private Cache<Integer, RoleState> pendingReplies =
68 - private RoleState pendingRole; 72 + CacheBuilder.newBuilder()
73 + .expireAfterWrite(pendingXidTimeoutSeconds, TimeUnit.SECONDS)
74 + .build();
69 75
70 // the expectation set by the caller for the returned role 76 // the expectation set by the caller for the returned role
71 private RoleRecvStatus expectation; 77 private RoleRecvStatus expectation;
...@@ -73,9 +79,6 @@ class RoleManager implements RoleHandler { ...@@ -73,9 +79,6 @@ class RoleManager implements RoleHandler {
73 79
74 80
75 public RoleManager(OpenFlowSwitchDriver sw) { 81 public RoleManager(OpenFlowSwitchDriver sw) {
76 - this.requestPending = false;
77 - this.pendingXid = -1;
78 - this.pendingRole = null;
79 this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE; 82 this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
80 this.sw = sw; 83 this.sw = sw;
81 } 84 }
...@@ -157,15 +160,11 @@ class RoleManager implements RoleHandler { ...@@ -157,15 +160,11 @@ class RoleManager implements RoleHandler {
157 } 160 }
158 // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn. 161 // OF1.0 switch with support for NX_ROLE_REQUEST vendor extn.
159 // make Role.EQUAL become Role.SLAVE 162 // make Role.EQUAL become Role.SLAVE
160 - pendingRole = role; 163 + RoleState roleToSend = (role == RoleState.EQUAL) ? RoleState.SLAVE : role;
161 - role = (role == RoleState.EQUAL) ? RoleState.SLAVE : role; 164 + pendingReplies.put(sendNxRoleRequest(roleToSend), role);
162 - pendingXid = sendNxRoleRequest(role);
163 - requestPending = true;
164 } else { 165 } else {
165 // OF1.3 switch, use OFPT_ROLE_REQUEST message 166 // OF1.3 switch, use OFPT_ROLE_REQUEST message
166 - pendingXid = sendOF13RoleRequest(role); 167 + pendingReplies.put(sendOF13RoleRequest(role), role);
167 - pendingRole = role;
168 - requestPending = true;
169 } 168 }
170 return true; 169 return true;
171 } 170 }
...@@ -192,12 +191,17 @@ class RoleManager implements RoleHandler { ...@@ -192,12 +191,17 @@ class RoleManager implements RoleHandler {
192 @Override 191 @Override
193 public synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri) 192 public synchronized RoleRecvStatus deliverRoleReply(RoleReplyInfo rri)
194 throws SwitchStateException { 193 throws SwitchStateException {
195 - if (!requestPending) { 194 + int xid = (int) rri.getXid();
195 + RoleState receivedRole = rri.getRole();
196 + RoleState expectedRole = pendingReplies.getIfPresent(xid);
197 +
198 + if (expectedRole == null) {
196 RoleState currentRole = (sw != null) ? sw.getRole() : null; 199 RoleState currentRole = (sw != null) ? sw.getRole() : null;
197 if (currentRole != null) { 200 if (currentRole != null) {
198 if (currentRole == rri.getRole()) { 201 if (currentRole == rri.getRole()) {
199 // Don't disconnect if the role reply we received is 202 // Don't disconnect if the role reply we received is
200 // for the same role we are already in. 203 // for the same role we are already in.
204 + // FIXME: but we do from the caller anyways.
201 log.debug("Received unexpected RoleReply from " 205 log.debug("Received unexpected RoleReply from "
202 + "Switch: {}. " 206 + "Switch: {}. "
203 + "Role in reply is same as current role of this " 207 + "Role in reply is same as current role of this "
...@@ -223,26 +227,24 @@ class RoleManager implements RoleHandler { ...@@ -223,26 +227,24 @@ class RoleManager implements RoleHandler {
223 return RoleRecvStatus.OTHER_EXPECTATION; 227 return RoleRecvStatus.OTHER_EXPECTATION;
224 } 228 }
225 229
226 - int xid = (int) rri.getXid();
227 - RoleState receivedRole = rri.getRole();
228 // XXX Should check generation id meaningfully and other cases of expectations 230 // XXX Should check generation id meaningfully and other cases of expectations
229 - 231 + //if (pendingXid != xid) {
230 - if (pendingXid != xid) { 232 + // log.info("Received older role reply from " +
231 - log.debug("Received older role reply from " + 233 + // "switch {} ({}). Ignoring. " +
232 - "switch {} ({}). Ignoring. " + 234 + // "Waiting for {}, xid={}",
233 - "Waiting for {}, xid={}", 235 + // new Object[] {sw.getStringId(), rri,
234 - new Object[] {sw.getStringId(), rri, 236 + // pendingRole, pendingXid });
235 - pendingRole, pendingXid }); 237 + // return RoleRecvStatus.OLD_REPLY;
236 - return RoleRecvStatus.OLD_REPLY; 238 + //}
237 - } 239 + sw.returnRoleReply(expectedRole, receivedRole);
238 - 240 +
239 - sw.returnRoleReply(pendingRole, receivedRole); 241 + if (expectedRole == receivedRole) {
240 -
241 - if (pendingRole == receivedRole) {
242 log.debug("Received role reply message from {} that matched " 242 log.debug("Received role reply message from {} that matched "
243 + "expected role-reply {} with expectations {}", 243 + "expected role-reply {} with expectations {}",
244 new Object[] {sw.getStringId(), receivedRole, expectation}); 244 new Object[] {sw.getStringId(), receivedRole, expectation});
245 245
246 + // Done with this RoleReply; Invalidate
247 + pendingReplies.invalidate(xid);
246 if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE || 248 if (expectation == RoleRecvStatus.MATCHED_CURRENT_ROLE ||
247 expectation == RoleRecvStatus.MATCHED_SET_ROLE) { 249 expectation == RoleRecvStatus.MATCHED_SET_ROLE) {
248 return expectation; 250 return expectation;
...@@ -251,6 +253,7 @@ class RoleManager implements RoleHandler { ...@@ -251,6 +253,7 @@ class RoleManager implements RoleHandler {
251 } 253 }
252 } 254 }
253 255
256 + pendingReplies.invalidate(xid);
254 // if xids match but role's don't, perhaps its a query (OF1.3) 257 // if xids match but role's don't, perhaps its a query (OF1.3)
255 if (expectation == RoleRecvStatus.REPLY_QUERY) { 258 if (expectation == RoleRecvStatus.REPLY_QUERY) {
256 return expectation; 259 return expectation;
...@@ -270,18 +273,17 @@ class RoleManager implements RoleHandler { ...@@ -270,18 +273,17 @@ class RoleManager implements RoleHandler {
270 @Override 273 @Override
271 public synchronized RoleRecvStatus deliverError(OFErrorMsg error) 274 public synchronized RoleRecvStatus deliverError(OFErrorMsg error)
272 throws SwitchStateException { 275 throws SwitchStateException {
273 - if (!requestPending) { 276 + RoleState errorRole = pendingReplies.getIfPresent(error.getXid());
274 - log.debug("Received an error msg from sw {}, but no pending " 277 + if (errorRole == null) {
275 - + "requests in role-changer; not handling ...",
276 - sw.getStringId());
277 - return RoleRecvStatus.OTHER_EXPECTATION;
278 - }
279 - if (pendingXid != error.getXid()) {
280 if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) { 278 if (error.getErrType() == OFErrorType.ROLE_REQUEST_FAILED) {
281 log.debug("Received an error msg from sw {} for a role request," 279 log.debug("Received an error msg from sw {} for a role request,"
282 + " but not for pending request in role-changer; " 280 + " but not for pending request in role-changer; "
283 + " ignoring error {} ...", 281 + " ignoring error {} ...",
284 sw.getStringId(), error); 282 sw.getStringId(), error);
283 + } else {
284 + log.debug("Received an error msg from sw {}, but no pending "
285 + + "requests in role-changer; not handling ...",
286 + sw.getStringId());
285 } 287 }
286 return RoleRecvStatus.OTHER_EXPECTATION; 288 return RoleRecvStatus.OTHER_EXPECTATION;
287 } 289 }
...@@ -292,7 +294,7 @@ class RoleManager implements RoleHandler { ...@@ -292,7 +294,7 @@ class RoleManager implements RoleHandler {
292 + "role-messaging is supported. Possible issues in " 294 + "role-messaging is supported. Possible issues in "
293 + "switch driver configuration?", new Object[] { 295 + "switch driver configuration?", new Object[] {
294 ((OFBadRequestErrorMsg) error).toString(), 296 ((OFBadRequestErrorMsg) error).toString(),
295 - sw.getStringId(), pendingRole 297 + sw.getStringId(), errorRole
296 }); 298 });
297 return RoleRecvStatus.UNSUPPORTED; 299 return RoleRecvStatus.UNSUPPORTED;
298 } 300 }
...@@ -316,7 +318,7 @@ class RoleManager implements RoleHandler { ...@@ -316,7 +318,7 @@ class RoleManager implements RoleHandler {
316 + "received Error to for pending role request [%s]. " 318 + "received Error to for pending role request [%s]. "
317 + "Error:[%s]. Disconnecting switch ... ", 319 + "Error:[%s]. Disconnecting switch ... ",
318 sw.getStringId(), 320 sw.getStringId(),
319 - pendingRole, rrerr); 321 + errorRole, rrerr);
320 throw new SwitchStateException(msgx); 322 throw new SwitchStateException(msgx);
321 default: 323 default:
322 break; 324 break;
......