blob: 8431068a6ef19f1443311f5ece2704818311e9e8 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
tom7ef8ff92014-09-17 13:08:06 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
tom7ef8ff92014-09-17 13:08:06 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.openflow.controller.driver;
tom7ef8ff92014-09-17 13:08:06 -070017
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070018import com.google.common.base.MoreObjects;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080019import com.google.common.collect.ImmutableList;
Brian O'Connore755caa2015-11-16 16:43:09 -080020import com.google.common.collect.Lists;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070021
Marc De Leenheerb9311372015-07-09 11:36:49 -070022import org.onosproject.net.Device;
alshabibb452fd72015-04-22 20:46:20 -070023import org.onosproject.net.driver.AbstractHandlerBehaviour;
Brian O'Connorabafb502014-12-02 22:26:20 -080024import org.onosproject.openflow.controller.Dpid;
Anton Chigrin4af4f872019-01-14 17:29:56 +020025import org.onosproject.openflow.controller.OpenFlowClassifier;
26import org.onosproject.openflow.controller.OpenFlowClassifierListener;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070027import org.onosproject.openflow.controller.OpenFlowSession;
Brian O'Connorabafb502014-12-02 22:26:20 -080028import org.onosproject.openflow.controller.RoleState;
tom7ef8ff92014-09-17 13:08:06 -070029import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
Jian Li152b8852015-12-07 14:47:25 -080030import org.projectfloodlight.openflow.protocol.OFErrorMsg;
Marc De Leenheerc662d322016-02-18 16:05:10 -080031import org.projectfloodlight.openflow.protocol.OFExperimenter;
32import org.projectfloodlight.openflow.protocol.OFFactories;
Jian Li152b8852015-12-07 14:47:25 -080033import org.projectfloodlight.openflow.protocol.OFFactory;
Marc De Leenheerc662d322016-02-18 16:05:10 -080034import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
35import org.projectfloodlight.openflow.protocol.OFMessage;
Jordi Ortizaa8de492016-12-01 00:21:36 +010036import org.projectfloodlight.openflow.protocol.OFMeterFeatures;
Jordi Ortiz91477b82016-11-29 15:22:50 +010037import org.projectfloodlight.openflow.protocol.OFMeterFeaturesStatsReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080038import org.projectfloodlight.openflow.protocol.OFNiciraControllerRoleRequest;
39import org.projectfloodlight.openflow.protocol.OFPortDesc;
40import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080041import org.projectfloodlight.openflow.protocol.OFPortReason;
Marc De Leenheerc662d322016-02-18 16:05:10 -080042import org.projectfloodlight.openflow.protocol.OFPortStatus;
Jian Li152b8852015-12-07 14:47:25 -080043import org.projectfloodlight.openflow.protocol.OFRoleReply;
Marc De Leenheerc662d322016-02-18 16:05:10 -080044import org.projectfloodlight.openflow.protocol.OFRoleRequest;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080045import org.projectfloodlight.openflow.protocol.OFType;
Marc De Leenheerc662d322016-02-18 16:05:10 -080046import org.projectfloodlight.openflow.protocol.OFVersion;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080047import org.projectfloodlight.openflow.types.OFPort;
tom7ef8ff92014-09-17 13:08:06 -070048import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
Thomas Vachuska1c681d72015-05-18 14:58:53 -070051import java.io.IOException;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080052import java.util.Collection;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070053import java.util.Collections;
54import java.util.List;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080055import java.util.Map;
56import java.util.concurrent.ConcurrentHashMap;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070057import java.util.concurrent.atomic.AtomicInteger;
Brian O'Connore755caa2015-11-16 16:43:09 -080058import java.util.concurrent.atomic.AtomicReference;
Thomas Vachuska1c681d72015-05-18 14:58:53 -070059import java.util.stream.Collectors;
60
tom7ef8ff92014-09-17 13:08:06 -070061/**
62 * An abstract representation of an OpenFlow switch. Can be extended by others
63 * to serve as a base for their vendor specific representation of a switch.
64 */
alshabibb452fd72015-04-22 20:46:20 -070065public abstract class AbstractOpenFlowSwitch extends AbstractHandlerBehaviour
66 implements OpenFlowSwitchDriver {
tom7ef8ff92014-09-17 13:08:06 -070067
Yuta HIGUCHIf5416d82014-10-24 21:17:40 -070068 protected final Logger log = LoggerFactory.getLogger(getClass());
tom7ef8ff92014-09-17 13:08:06 -070069
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070070 private OpenFlowSession channel;
Ray Milkeye53f1712015-01-16 09:17:16 -080071 protected String channelId;
tom7ef8ff92014-09-17 13:08:06 -070072
73 private boolean connected;
74 protected boolean startDriverHandshakeCalled = false;
alshabibb452fd72015-04-22 20:46:20 -070075 private Dpid dpid;
tom7ef8ff92014-09-17 13:08:06 -070076 private OpenFlowAgent agent;
77 private final AtomicInteger xidCounter = new AtomicInteger(0);
78
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -070079 private OFFactory ofFactory;
tom7ef8ff92014-09-17 13:08:06 -070080
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -080081 // known port descriptions maintained by
82 // (all) : OFPortStatus
83 // < OF1.3 : feature reply
84 // >= OF1.3 : multipart stats reply (OFStatsReply:PORT_DESC)
85 private Map<OFPort, OFPortDesc> portDescs = new ConcurrentHashMap<>();
86
Ray Milkey7f98ba62018-09-05 16:14:08 -070087 private List<OFPortDescStatsReply> ports = Lists.newCopyOnWriteArrayList();
tom7ef8ff92014-09-17 13:08:06 -070088
Ray Milkey7f98ba62018-09-05 16:14:08 -070089 private boolean tableFull;
tom7ef8ff92014-09-17 13:08:06 -070090
91 private RoleHandler roleMan;
92
Brian O'Connore755caa2015-11-16 16:43:09 -080093 // TODO this is accessed from multiple threads, but volatile may have performance implications
94 protected volatile RoleState role;
tom7ef8ff92014-09-17 13:08:06 -070095
Ray Milkey7f98ba62018-09-05 16:14:08 -070096 private OFFeaturesReply features;
tom7ef8ff92014-09-17 13:08:06 -070097
Ray Milkey7f98ba62018-09-05 16:14:08 -070098 private OFDescStatsReply desc;
99
100 private OFMeterFeaturesStatsReply meterfeatures;
Jordi Ortiz91477b82016-11-29 15:22:50 +0100101
Anton Chigrin4af4f872019-01-14 17:29:56 +0200102 protected OpenFlowClassifierListener classifierListener = new InternalClassifierListener();
103
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800104 // messagesPendingMastership is used as synchronization variable for
105 // all mastership related changes. In this block, mastership (including
106 // role update) will have either occurred or not.
Brian O'Connore755caa2015-11-16 16:43:09 -0800107 private final AtomicReference<List<OFMessage>> messagesPendingMastership
108 = new AtomicReference<>();
Charles Chan5b7ec342015-10-18 20:55:41 -0700109
alshabibb452fd72015-04-22 20:46:20 -0700110 @Override
111 public void init(Dpid dpid, OFDescStatsReply desc, OFVersion ofv) {
tom7ef8ff92014-09-17 13:08:06 -0700112 this.dpid = dpid;
113 this.desc = desc;
114 }
115
116 //************************
117 // Channel related
118 //************************
119
120 @Override
121 public final void disconnectSwitch() {
Charles Chanecfdfb72015-11-24 19:05:50 -0800122 setConnected(false);
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700123 this.channel.closeSession();
tom7ef8ff92014-09-17 13:08:06 -0700124 }
125
126 @Override
Charles Chan5b7ec342015-10-18 20:55:41 -0700127 public void sendMsg(OFMessage msg) {
128 this.sendMsg(Collections.singletonList(msg));
tom7ef8ff92014-09-17 13:08:06 -0700129 }
130
131 @Override
132 public final void sendMsg(List<OFMessage> msgs) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800133 /*
134 It is possible that in this block, we transition to SLAVE/EQUAL.
135 If this is the case, the supplied messages will race with the
136 RoleRequest message, and they could be rejected by the switch.
137 In the interest of performance, we will not protect this block with
138 a synchronization primitive, because the message would have just been
139 dropped anyway.
140 */
Jian Lia78cdb22016-04-21 13:03:58 -0700141
Brian O'Connore755caa2015-11-16 16:43:09 -0800142 if (role == RoleState.MASTER) {
143 // fast path send when we are master
Brian O'Connore755caa2015-11-16 16:43:09 -0800144 sendMsgsOnChannel(msgs);
145 return;
146 }
147 // check to see if mastership transition is in progress
148 synchronized (messagesPendingMastership) {
149 /*
150 messagesPendingMastership is used as synchronization variable for
151 all mastership related changes. In this block, mastership (including
152 role update) will have either occurred or not.
153 */
154 if (role == RoleState.MASTER) {
155 // transition to MASTER complete, send messages
156 sendMsgsOnChannel(msgs);
157 return;
158 }
159
160 List<OFMessage> messages = messagesPendingMastership.get();
161 if (messages != null) {
162 // we are transitioning to MASTER, so add messages to queue
163 messages.addAll(msgs);
164 log.debug("Enqueue message for switch {}. queue size after is {}",
165 dpid, messages.size());
166 } else {
167 // not transitioning to MASTER
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700168 log.warn("Dropping message for switch {} (role: {}, active: {}): {}",
169 dpid, role, channel.isActive(), msgs);
Brian O'Connore755caa2015-11-16 16:43:09 -0800170 }
171 }
Jian Li11111972016-04-01 23:49:00 -0700172 }
Jian Li152b8852015-12-07 14:47:25 -0800173
Brian O'Connore755caa2015-11-16 16:43:09 -0800174 private void sendMsgsOnChannel(List<OFMessage> msgs) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700175 if (channel.sendMsg(msgs)) {
Jian Lia78cdb22016-04-21 13:03:58 -0700176 agent.processDownstreamMessage(dpid, msgs);
Charles Chan5b7ec342015-10-18 20:55:41 -0700177 } else {
Brian O'Connore755caa2015-11-16 16:43:09 -0800178 log.warn("Dropping messages for switch {} because channel is not connected: {}",
179 dpid, msgs);
alshabib339a3d92014-09-26 17:54:32 -0700180 }
tom7ef8ff92014-09-17 13:08:06 -0700181 }
182
183 @Override
alshabibb452fd72015-04-22 20:46:20 -0700184 public final void sendRoleRequest(OFMessage msg) {
185 if (msg instanceof OFRoleRequest ||
186 msg instanceof OFNiciraControllerRoleRequest) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800187 sendMsgsOnChannel(Collections.singletonList(msg));
alshabibb452fd72015-04-22 20:46:20 -0700188 return;
189 }
190 throw new IllegalArgumentException("Someone is trying to send " +
191 "a non role request message");
192 }
tom7ef8ff92014-09-17 13:08:06 -0700193
Ayaka Koshibe3c240772015-05-20 16:23:40 -0700194 @Override
Marc De Leenheerc662d322016-02-18 16:05:10 -0800195 public final void
196 sendHandshakeMessage(OFMessage message) {
alshabiba2df7b2a2015-05-06 13:57:10 -0700197 if (!this.isDriverHandshakeComplete()) {
Brian O'Connore755caa2015-11-16 16:43:09 -0800198 sendMsgsOnChannel(Collections.singletonList(message));
alshabiba2df7b2a2015-05-06 13:57:10 -0700199 }
200 }
201
tom7ef8ff92014-09-17 13:08:06 -0700202 @Override
203 public final boolean isConnected() {
204 return this.connected;
205 }
206
207 @Override
208 public final void setConnected(boolean connected) {
209 this.connected = connected;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700210 }
tom7ef8ff92014-09-17 13:08:06 -0700211
212 @Override
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700213 public final void setChannel(OpenFlowSession channel) {
tom7ef8ff92014-09-17 13:08:06 -0700214 this.channel = channel;
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700215 channelId = channel.sessionInfo().toString();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700216 }
tom7ef8ff92014-09-17 13:08:06 -0700217
Ray Milkeye53f1712015-01-16 09:17:16 -0800218 @Override
219 public String channelId() {
220 return channelId;
221 }
222
tom7ef8ff92014-09-17 13:08:06 -0700223 //************************
224 // Switch features related
225 //************************
226
227 @Override
228 public final long getId() {
229 return this.dpid.value();
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700230 }
tom7ef8ff92014-09-17 13:08:06 -0700231
232 @Override
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700233 public Dpid getDpid() {
234 return this.dpid;
235 }
236
237 @Override
tom7ef8ff92014-09-17 13:08:06 -0700238 public final String getStringId() {
239 return this.dpid.toString();
240 }
241
242 @Override
243 public final void setOFVersion(OFVersion ofV) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700244 this.ofFactory = OFFactories.getFactory(ofV);
tom7ef8ff92014-09-17 13:08:06 -0700245 }
246
247 @Override
248 public void setTableFull(boolean full) {
249 this.tableFull = full;
250 }
251
252 @Override
253 public void setFeaturesReply(OFFeaturesReply featuresReply) {
254 this.features = featuresReply;
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800255 if (featuresReply.getVersion().compareTo(OFVersion.OF_13) < 0) {
256 // before OF 1.3, feature reply contains OFPortDescs
257 replacePortDescsWith(featuresReply.getPorts());
258 }
tom7ef8ff92014-09-17 13:08:06 -0700259 }
260
261 @Override
Jordi Ortiz91477b82016-11-29 15:22:50 +0100262 public void setMeterFeaturesReply(OFMeterFeaturesStatsReply meterFeaturesReply) {
263 meterfeatures = meterFeaturesReply;
264 }
265
266 @Override
tom7ef8ff92014-09-17 13:08:06 -0700267 public abstract Boolean supportNxRole();
268
269 //************************
270 // Message handling
271 //************************
272 /**
273 * Handle the message coming from the dataplane.
274 *
275 * @param m the actual message
276 */
277 @Override
278 public final void handleMessage(OFMessage m) {
Thomas Vachuska39274462014-12-02 13:23:50 -0800279 if (this.role == RoleState.MASTER || m instanceof OFPortStatus) {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700280 try {
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800281 // TODO revisit states other than ports should
282 // also ignore role state.
283 if (m.getType() == OFType.PORT_STATUS) {
284 OFPortStatus portStatus = (OFPortStatus) m;
285 if (portStatus.getReason() == OFPortReason.DELETE) {
286 portDescs.remove(portStatus.getDesc().getPortNo());
287 } else {
288 portDescs.put(portStatus.getDesc().getPortNo(), portStatus.getDesc());
289 }
290 }
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700291 this.agent.processMessage(dpid, m);
292 } catch (Exception e) {
Ray Milkey31b00482019-02-07 08:06:28 -0800293 log.warn("Unhandled exception processing {}@{}:{}", m, dpid, e.getMessage());
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700294 }
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800295 } else {
296 log.trace("Dropping received message {}, was not MASTER", m);
alshabib339a3d92014-09-26 17:54:32 -0700297 }
tom7ef8ff92014-09-17 13:08:06 -0700298 }
299
300 @Override
301 public RoleState getRole() {
302 return role;
Thomas Vachuska1c681d72015-05-18 14:58:53 -0700303 }
tom7ef8ff92014-09-17 13:08:06 -0700304
305 @Override
306 public final boolean connectSwitch() {
Anton Chigrin4af4f872019-01-14 17:29:56 +0200307 boolean status = this.agent.addConnectedSwitch(dpid, this);
308 if (status) {
309 this.agent.addClassifierListener(classifierListener);
310 }
311 return status;
tom7ef8ff92014-09-17 13:08:06 -0700312 }
313
314 @Override
315 public final boolean activateMasterSwitch() {
316 return this.agent.addActivatedMasterSwitch(dpid, this);
317 }
318
319 @Override
320 public final boolean activateEqualSwitch() {
321 return this.agent.addActivatedEqualSwitch(dpid, this);
322 }
323
324 @Override
325 public final void transitionToEqualSwitch() {
326 this.agent.transitionToEqualSwitch(dpid);
327 }
328
329 @Override
330 public final void transitionToMasterSwitch() {
331 this.agent.transitionToMasterSwitch(dpid);
Brian O'Connore755caa2015-11-16 16:43:09 -0800332 synchronized (messagesPendingMastership) {
333 List<OFMessage> messages = messagesPendingMastership.get();
Jonathan Hart39e20232018-01-29 16:02:41 -0800334 if (messages != null && !messages.isEmpty()) {
HIGUCHI Yuta1979f552015-12-28 21:24:26 -0800335 // Cannot use sendMsg here. It will only append to pending list.
336 sendMsgsOnChannel(messages);
Brian O'Connore755caa2015-11-16 16:43:09 -0800337 log.debug("Sending {} pending messages to switch {}",
338 messages.size(), dpid);
339 messagesPendingMastership.set(null);
340 }
341 // perform role transition after clearing messages queue
342 this.role = RoleState.MASTER;
Charles Chan5b7ec342015-10-18 20:55:41 -0700343 }
tom7ef8ff92014-09-17 13:08:06 -0700344 }
345
346 @Override
347 public final void removeConnectedSwitch() {
348 this.agent.removeConnectedSwitch(dpid);
Anton Chigrin4af4f872019-01-14 17:29:56 +0200349 this.agent.removeClassifierListener(classifierListener);
tom7ef8ff92014-09-17 13:08:06 -0700350 }
351
352 @Override
353 public OFFactory factory() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700354 return ofFactory;
tom7ef8ff92014-09-17 13:08:06 -0700355 }
356
357 @Override
358 public void setPortDescReply(OFPortDescStatsReply portDescReply) {
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800359 portDescReply.getEntries().forEach(pd -> portDescs.put(pd.getPortNo(), pd));
360
361 // maintaining only for backward compatibility, to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700362 this.ports.add(portDescReply);
363 }
364
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800365 protected void replacePortDescsWith(Collection<OFPortDesc> allPorts) {
366 Map<OFPort, OFPortDesc> ports = new ConcurrentHashMap<>(allPorts.size());
367 allPorts.forEach(pd -> ports.put(pd.getPortNo(), pd));
368 // replace all
369 this.portDescs = ports;
370 }
371
372 protected Map<OFPort, OFPortDesc> portDescs() {
373 return portDescs;
374 }
375
376 // only called once during handshake WAIT_DESCRIPTION_STAT_REPLY
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700377 @Override
378 public void setPortDescReplies(List<OFPortDescStatsReply> portDescReplies) {
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800379 replacePortDescsWith(portDescReplies.stream()
380 .map(OFPortDescStatsReply::getEntries)
381 .flatMap(List::stream)
382 .collect(Collectors.toList()));
383
384 // maintaining only for backward compatibility, to be removed
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700385 this.ports.addAll(portDescReplies);
tom7ef8ff92014-09-17 13:08:06 -0700386 }
387
388 @Override
Ayaka Koshibe3ef2b0d2014-10-31 13:58:27 -0700389 public void returnRoleReply(RoleState requested, RoleState response) {
390 this.agent.returnRoleReply(dpid, requested, response);
Ayaka Koshibeab91cc42014-09-25 10:20:52 -0700391 }
392
393 @Override
tom7ef8ff92014-09-17 13:08:06 -0700394 public abstract void startDriverHandshake();
395
396 @Override
397 public abstract boolean isDriverHandshakeComplete();
398
399 @Override
400 public abstract void processDriverHandshakeMessage(OFMessage m);
401
alshabib339a3d92014-09-26 17:54:32 -0700402
403 // Role Handling
404
tom7ef8ff92014-09-17 13:08:06 -0700405 @Override
406 public void setRole(RoleState role) {
407 try {
Brian O'Connore755caa2015-11-16 16:43:09 -0800408 if (role == RoleState.SLAVE || role == RoleState.EQUAL) {
409 // perform role transition to SLAVE/EQUAL before sending role request
410 this.role = role;
411 }
tom7ef8ff92014-09-17 13:08:06 -0700412 if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
Madan Jampanif2af7712015-05-29 18:43:52 -0700413 log.debug("Sending role {} to switch {}", role, getStringId());
Brian O'Connore755caa2015-11-16 16:43:09 -0800414 if (role == RoleState.MASTER) {
415 synchronized (messagesPendingMastership) {
416 if (messagesPendingMastership.get() == null) {
417 log.debug("Initializing new message queue for switch {}", dpid);
418 /*
419 The presence of messagesPendingMastership indicates that
420 a switch is currently transitioning to MASTER, but
421 is still awaiting role reply from switch.
422 */
423 messagesPendingMastership.set(Lists.newArrayList());
424 }
Charles Chan5b7ec342015-10-18 20:55:41 -0700425 }
alshabib339a3d92014-09-26 17:54:32 -0700426 }
Brian O'Connore755caa2015-11-16 16:43:09 -0800427 } else if (role == RoleState.MASTER) {
428 // role request not support; transition switch to MASTER
alshabib7814e9f2014-09-30 11:52:12 -0700429 this.role = role;
tom7ef8ff92014-09-17 13:08:06 -0700430 }
431 } catch (IOException e) {
432 log.error("Unable to write to switch {}.", this.dpid);
433 }
434 }
435
alshabib339a3d92014-09-26 17:54:32 -0700436 @Override
437 public void reassertRole() {
Brian O'Connore755caa2015-11-16 16:43:09 -0800438 // TODO should messages be sent directly or queue during reassertion?
alshabib339a3d92014-09-26 17:54:32 -0700439 if (this.getRole() == RoleState.MASTER) {
440 log.warn("Received permission error from switch {} while " +
441 "being master. Reasserting master role.",
442 this.getStringId());
443 this.setRole(RoleState.MASTER);
444 }
445 }
446
tom7ef8ff92014-09-17 13:08:06 -0700447 @Override
448 public void handleRole(OFMessage m) throws SwitchStateException {
449 RoleReplyInfo rri = roleMan.extractOFRoleReply((OFRoleReply) m);
450 RoleRecvStatus rrs = roleMan.deliverRoleReply(rri);
451 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
452 if (rri.getRole() == RoleState.MASTER) {
453 this.transitionToMasterSwitch();
454 } else if (rri.getRole() == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800455 rri.getRole() == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700456 this.transitionToEqualSwitch();
457 }
alshabib339a3d92014-09-26 17:54:32 -0700458 } else {
alshabib4785eec2014-12-04 16:45:45 -0800459 log.warn("Failed to set role for {}", this.getStringId());
tom7ef8ff92014-09-17 13:08:06 -0700460 }
461 }
462
463 @Override
464 public void handleNiciraRole(OFMessage m) throws SwitchStateException {
465 RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
466 if (r == null) {
467 // The message wasn't really a Nicira role reply. We just
468 // dispatch it to the OFMessage listeners in this case.
469 this.handleMessage(m);
alshabibdfc7afb2014-10-21 20:13:27 -0700470 return;
tom7ef8ff92014-09-17 13:08:06 -0700471 }
472
473 RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
474 new RoleReplyInfo(r, null, m.getXid()));
475 if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
476 if (r == RoleState.MASTER) {
477 this.transitionToMasterSwitch();
478 } else if (r == RoleState.EQUAL ||
Brian O'Connore755caa2015-11-16 16:43:09 -0800479 r == RoleState.SLAVE) {
tom7ef8ff92014-09-17 13:08:06 -0700480 this.transitionToEqualSwitch();
481 }
alshabib339a3d92014-09-26 17:54:32 -0700482 } else {
alshabibdfc7afb2014-10-21 20:13:27 -0700483 this.disconnectSwitch();
tom7ef8ff92014-09-17 13:08:06 -0700484 }
485 }
486
487 @Override
488 public boolean handleRoleError(OFErrorMsg error) {
489 try {
490 return RoleRecvStatus.OTHER_EXPECTATION != this.roleMan.deliverError(error);
491 } catch (SwitchStateException e) {
492 this.disconnectSwitch();
493 }
494 return true;
495 }
496
tom7ef8ff92014-09-17 13:08:06 -0700497 @Override
498 public final void setAgent(OpenFlowAgent ag) {
499 if (this.agent == null) {
500 this.agent = ag;
501 }
502 }
503
504 @Override
505 public final void setRoleHandler(RoleHandler roleHandler) {
506 if (this.roleMan == null) {
507 this.roleMan = roleHandler;
508 }
509 }
510
511 @Override
512 public void setSwitchDescription(OFDescStatsReply d) {
513 this.desc = d;
514 }
515
516 @Override
517 public int getNextTransactionId() {
518 return this.xidCounter.getAndIncrement();
519 }
520
521 @Override
522 public List<OFPortDesc> getPorts() {
Yuta HIGUCHIf83c8cf2017-12-17 14:33:49 -0800523 return ImmutableList.copyOf(portDescs.values());
tom7ef8ff92014-09-17 13:08:06 -0700524 }
525
526 @Override
Jordi Ortizaa8de492016-12-01 00:21:36 +0100527 public OFMeterFeatures getMeterFeatures() {
528 if (this.meterfeatures != null) {
529 return this.meterfeatures.getFeatures();
530 } else {
531 return null;
532 }
533 }
534
535 @Override
Laszlo Pappedadbe22017-12-14 20:05:49 +0000536 public OFFeaturesReply features() {
537 return this.features;
538 }
539
540 @Override
Ray Milkeyd3edd032015-01-16 11:38:58 -0800541 public String manufacturerDescription() {
tom7ef8ff92014-09-17 13:08:06 -0700542 return this.desc.getMfrDesc();
543 }
544
tom7ef8ff92014-09-17 13:08:06 -0700545 @Override
546 public String datapathDescription() {
547 return this.desc.getDpDesc();
548 }
549
tom7ef8ff92014-09-17 13:08:06 -0700550 @Override
551 public String hardwareDescription() {
552 return this.desc.getHwDesc();
553 }
554
555 @Override
556 public String softwareDescription() {
557 return this.desc.getSwDesc();
558 }
559
560 @Override
561 public String serialNumber() {
562 return this.desc.getSerialNum();
563 }
564
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700565 @Override
Marc De Leenheerb9311372015-07-09 11:36:49 -0700566 public Device.Type deviceType() {
567 return Device.Type.SWITCH;
Praseed Balakrishnana22eadf2014-10-20 14:21:45 -0700568 }
569
alshabibb452fd72015-04-22 20:46:20 -0700570 @Override
571 public String toString() {
Yuta HIGUCHI6ee6b8c2017-05-09 14:44:30 -0700572 return MoreObjects.toStringHelper(getClass())
573 .add("session", channel.sessionInfo())
574 .add("dpid", dpid)
575 .toString();
alshabibb452fd72015-04-22 20:46:20 -0700576 }
Anton Chigrin4af4f872019-01-14 17:29:56 +0200577
578 private class InternalClassifierListener implements OpenFlowClassifierListener {
579
580 @Override
581 public void handleClassifiersAdd(OpenFlowClassifier classifier) {
582 channel.addClassifier(classifier);
583 }
584
585 @Override
586 public void handleClassifiersRemove(OpenFlowClassifier classifier) {
587 channel.removeClassifier(classifier);
588 }
589 }
tom7ef8ff92014-09-17 13:08:06 -0700590}