alshabib

switch can now connect

...@@ -13,7 +13,7 @@ public interface OpenFlowSwitch { ...@@ -13,7 +13,7 @@ public interface OpenFlowSwitch {
13 * 13 *
14 * @param msg the message to write 14 * @param msg the message to write
15 */ 15 */
16 - public void write(OFMessage msg); 16 + public void sendMsg(OFMessage msg);
17 17
18 /** 18 /**
19 * Handle a message from the switch. 19 * Handle a message from the switch.
......
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
18 package org.onlab.onos.of.controller.impl.internal; 18 package org.onlab.onos.of.controller.impl.internal;
19 19
20 import java.io.IOException; 20 import java.io.IOException;
21 +import java.util.Collections;
21 import java.util.List; 22 import java.util.List;
23 +import java.util.concurrent.atomic.AtomicInteger;
22 24
23 import org.jboss.netty.channel.Channel; 25 import org.jboss.netty.channel.Channel;
24 import org.onlab.onos.of.controller.Dpid; 26 import org.onlab.onos.of.controller.Dpid;
...@@ -27,12 +29,14 @@ import org.onlab.onos.of.controller.RoleState; ...@@ -27,12 +29,14 @@ import org.onlab.onos.of.controller.RoleState;
27 import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent; 29 import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
28 import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus; 30 import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleRecvStatus;
29 import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo; 31 import org.onlab.onos.of.controller.impl.internal.RoleManager.RoleReplyInfo;
32 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
30 import org.projectfloodlight.openflow.protocol.OFErrorMsg; 33 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
31 import org.projectfloodlight.openflow.protocol.OFExperimenter; 34 import org.projectfloodlight.openflow.protocol.OFExperimenter;
32 import org.projectfloodlight.openflow.protocol.OFFactories; 35 import org.projectfloodlight.openflow.protocol.OFFactories;
33 import org.projectfloodlight.openflow.protocol.OFFactory; 36 import org.projectfloodlight.openflow.protocol.OFFactory;
34 import org.projectfloodlight.openflow.protocol.OFFeaturesReply; 37 import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
35 import org.projectfloodlight.openflow.protocol.OFMessage; 38 import org.projectfloodlight.openflow.protocol.OFMessage;
39 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
36 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply; 40 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
37 import org.projectfloodlight.openflow.protocol.OFRoleReply; 41 import org.projectfloodlight.openflow.protocol.OFRoleReply;
38 import org.projectfloodlight.openflow.protocol.OFVersion; 42 import org.projectfloodlight.openflow.protocol.OFVersion;
...@@ -45,10 +49,13 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -45,10 +49,13 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
45 private static Logger log = 49 private static Logger log =
46 LoggerFactory.getLogger(AbstractOpenFlowSwitch.class); 50 LoggerFactory.getLogger(AbstractOpenFlowSwitch.class);
47 51
48 - private Channel channel; 52 + protected Channel channel;
53 + protected boolean startDriverHandshakeCalled = false;
54 +
49 private boolean connected; 55 private boolean connected;
50 private Dpid dpid; 56 private Dpid dpid;
51 private OpenFlowSwitchAgent agent; 57 private OpenFlowSwitchAgent agent;
58 + private AtomicInteger xidCounter = new AtomicInteger(0);
52 59
53 private OFVersion ofVersion; 60 private OFVersion ofVersion;
54 61
...@@ -58,8 +65,12 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -58,8 +65,12 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
58 65
59 private final RoleManager roleMan = new RoleManager(this); 66 private final RoleManager roleMan = new RoleManager(this);
60 67
61 - protected AbstractOpenFlowSwitch(long dpid) { 68 + protected RoleState role;
62 - this.dpid = new Dpid(dpid); 69 +
70 + protected OFFeaturesReply features;
71 +
72 + protected AbstractOpenFlowSwitch(Dpid dp) {
73 + this.dpid = dp;
63 } 74 }
64 75
65 //************************ 76 //************************
...@@ -80,14 +91,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -80,14 +91,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
80 * 91 *
81 * @param m the message to be written 92 * @param m the message to be written
82 */ 93 */
83 - public abstract void write(OFMessage m); 94 + public abstract void sendMsg(OFMessage m);
84 95
85 /** 96 /**
86 * Writes to the OFMessage list to the output stream. 97 * Writes to the OFMessage list to the output stream.
87 * 98 *
88 * @param msgs the messages to be written 99 * @param msgs the messages to be written
89 */ 100 */
90 - public abstract void write(List<OFMessage> msgs); 101 + public void write(List<OFMessage> msgs) {
102 + this.channel.write(msgs);
103 + }
91 104
92 105
93 /** 106 /**
...@@ -151,7 +164,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -151,7 +164,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
151 this.tableFull = full; 164 this.tableFull = full;
152 } 165 }
153 166
154 - public abstract void setFeaturesReply(OFFeaturesReply featuresReply); 167 + public void setFeaturesReply(OFFeaturesReply featuresReply) {
168 + this.features = featuresReply;
169 + }
155 170
156 /** 171 /**
157 * Let peoeple know if you support Nicira style role requests. 172 * Let peoeple know if you support Nicira style role requests.
...@@ -172,7 +187,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -172,7 +187,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
172 this.agent.processMessage(m); 187 this.agent.processMessage(m);
173 } 188 }
174 189
175 - public abstract RoleState getRole(); 190 + public RoleState getRole() {
191 + return role;
192 + };
176 193
177 final boolean addConnectedSwitch() { 194 final boolean addConnectedSwitch() {
178 return this.agent.addConnectedSwitch(this.getId(), this); 195 return this.agent.addConnectedSwitch(this.getId(), this);
...@@ -214,7 +231,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -214,7 +231,9 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
214 231
215 public void setRole(RoleState role) { 232 public void setRole(RoleState role) {
216 try { 233 try {
217 - this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE); 234 + if (this.roleMan.sendRoleRequest(role, RoleRecvStatus.MATCHED_SET_ROLE)) {
235 + this.role = role;
236 + }
218 } catch (IOException e) { 237 } catch (IOException e) {
219 log.error("Unable to write to switch {}.", this.dpid); 238 log.error("Unable to write to switch {}.", this.dpid);
220 } 239 }
...@@ -236,23 +255,23 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -236,23 +255,23 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
236 } 255 }
237 256
238 void handleNiciraRole(OFMessage m) throws SwitchStateException { 257 void handleNiciraRole(OFMessage m) throws SwitchStateException {
239 - RoleState role = this.roleMan.extractNiciraRoleReply((OFExperimenter) m); 258 + RoleState r = this.roleMan.extractNiciraRoleReply((OFExperimenter) m);
240 - if (role == null) { 259 + if (r == null) {
241 - // The message wasn't really a Nicira role reply. We just 260 + // The message wasn't really a Nicira role reply. We just
242 - // dispatch it to the OFMessage listeners in this case. 261 + // dispatch it to the OFMessage listeners in this case.
243 - this.handleMessage(m); 262 + this.handleMessage(m);
244 - } 263 + }
245 - 264 +
246 - RoleRecvStatus rrs = this.roleMan.deliverRoleReply( 265 + RoleRecvStatus rrs = this.roleMan.deliverRoleReply(
247 - new RoleReplyInfo(role, null, m.getXid())); 266 + new RoleReplyInfo(r, null, m.getXid()));
248 - if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) { 267 + if (rrs == RoleRecvStatus.MATCHED_SET_ROLE) {
249 - if (role == RoleState.MASTER) { 268 + if (r == RoleState.MASTER) {
250 - this.transitionToMasterSwitch(); 269 + this.transitionToMasterSwitch();
251 - } else if (role == RoleState.EQUAL || 270 + } else if (r == RoleState.EQUAL ||
252 - role == RoleState.SLAVE) { 271 + r == RoleState.SLAVE) {
253 - this.transitionToEqualSwitch(); 272 + this.transitionToEqualSwitch();
254 - } 273 + }
255 - } 274 + }
256 } 275 }
257 276
258 boolean handleRoleError(OFErrorMsg error) { 277 boolean handleRoleError(OFErrorMsg error) {
...@@ -274,6 +293,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch { ...@@ -274,6 +293,16 @@ public abstract class AbstractOpenFlowSwitch implements OpenFlowSwitch {
274 this.agent = ag; 293 this.agent = ag;
275 } 294 }
276 295
296 + public void setSwitchDescription(OFDescStatsReply desc) {
297 + // TODO Auto-generated method stub
298 + }
299 +
300 + protected int getNextTransactionId() {
301 + return this.xidCounter.getAndIncrement();
302 + }
277 303
304 + protected List<OFPortDesc> getPorts() {
305 + return Collections.unmodifiableList(ports.getEntries());
306 + }
278 307
279 } 308 }
......
...@@ -29,9 +29,11 @@ import org.jboss.netty.channel.ChannelPipelineFactory; ...@@ -29,9 +29,11 @@ import org.jboss.netty.channel.ChannelPipelineFactory;
29 import org.jboss.netty.channel.group.ChannelGroup; 29 import org.jboss.netty.channel.group.ChannelGroup;
30 import org.jboss.netty.channel.group.DefaultChannelGroup; 30 import org.jboss.netty.channel.group.DefaultChannelGroup;
31 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; 31 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
32 +import org.onlab.onos.of.controller.Dpid;
32 import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc; 33 import org.onlab.onos.of.controller.impl.annotations.LogMessageDoc;
33 import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs; 34 import org.onlab.onos.of.controller.impl.annotations.LogMessageDocs;
34 import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent; 35 import org.onlab.onos.of.controller.impl.internal.OpenFlowControllerImpl.OpenFlowSwitchAgent;
36 +import org.onlab.onos.of.drivers.DriverManager;
35 import org.projectfloodlight.openflow.protocol.OFDescStatsReply; 37 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
36 import org.projectfloodlight.openflow.protocol.OFFactories; 38 import org.projectfloodlight.openflow.protocol.OFFactories;
37 import org.projectfloodlight.openflow.protocol.OFFactory; 39 import org.projectfloodlight.openflow.protocol.OFFactory;
...@@ -83,11 +85,6 @@ public class Controller { ...@@ -83,11 +85,6 @@ public class Controller {
83 // Getters/Setters 85 // Getters/Setters
84 // *************** 86 // ***************
85 87
86 -
87 - public synchronized void setIOFSwitchManager(IOFSwitchManager swManager) {
88 - this.switchManager = swManager;
89 - }
90 -
91 public OFFactory getOFMessageFactory10() { 88 public OFFactory getOFMessageFactory10() {
92 return FACTORY10; 89 return FACTORY10;
93 } 90 }
...@@ -201,18 +198,6 @@ public class Controller { ...@@ -201,18 +198,6 @@ public class Controller {
201 198
202 } 199 }
203 200
204 - /**
205 - * Startup all of the controller's components.
206 - */
207 - @LogMessageDoc(message = "Waiting for storage source",
208 - explanation = "The system database is not yet ready",
209 - recommendation = "If this message persists, this indicates " +
210 - "that the system database has failed to start. " +
211 - LogMessageDoc.CHECK_CONTROLLER)
212 - public synchronized void startupComponents() {
213 - //TODO do something maybe
214 - }
215 -
216 // ************** 201 // **************
217 // Utility methods 202 // Utility methods
218 // ************** 203 // **************
...@@ -236,9 +221,10 @@ public class Controller { ...@@ -236,9 +221,10 @@ public class Controller {
236 * @param desc 221 * @param desc
237 * @return switch instance 222 * @return switch instance
238 */ 223 */
239 - protected AbstractOpenFlowSwitch getOFSwitchInstance(OFDescStatsReply desc, OFVersion ofv) { 224 + protected AbstractOpenFlowSwitch getOFSwitchInstance(long dpid,
240 - AbstractOpenFlowSwitch sw = switchManager.getSwitchImpl(desc.getMfrDesc(), desc.getHwDesc(), 225 + OFDescStatsReply desc, OFVersion ofv) {
241 - desc.getSwDesc(), ofv); 226 + AbstractOpenFlowSwitch sw = DriverManager.getOFSwitchImpl(new Dpid(dpid),
227 + desc, ofv);
242 sw.setAgent(agent); 228 sw.setAgent(agent);
243 return sw; 229 return sw;
244 } 230 }
...@@ -247,7 +233,6 @@ public class Controller { ...@@ -247,7 +233,6 @@ public class Controller {
247 log.info("Initialising OpenFlow Lib and IO"); 233 log.info("Initialising OpenFlow Lib and IO");
248 this.agent = ag; 234 this.agent = ag;
249 this.init(new HashMap<String, String>()); 235 this.init(new HashMap<String, String>());
250 - this.startupComponents();
251 this.run(); 236 this.run();
252 } 237 }
253 238
......
...@@ -230,12 +230,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -230,12 +230,6 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
230 h.thisdpid = m.getDatapathId().getLong(); 230 h.thisdpid = m.getDatapathId().getLong();
231 log.info("Received features reply for switch at {} with dpid {}", 231 log.info("Received features reply for switch at {} with dpid {}",
232 h.getSwitchInfoString(), h.thisdpid); 232 h.getSwitchInfoString(), h.thisdpid);
233 - //update the controller about this connected switch
234 - boolean success = h.sw.addConnectedSwitch();
235 - if (!success) {
236 - disconnectDuplicate(h);
237 - return;
238 - }
239 233
240 h.featuresReply = m; //temp store 234 h.featuresReply = m; //temp store
241 if (h.ofVersion == OFVersion.OF_10) { 235 if (h.ofVersion == OFVersion.OF_10) {
...@@ -419,7 +413,12 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -419,7 +413,12 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
419 h.channel.getRemoteAddress()); 413 h.channel.getRemoteAddress());
420 OFDescStatsReply drep = (OFDescStatsReply) m; 414 OFDescStatsReply drep = (OFDescStatsReply) m;
421 // Here is where we differentiate between different kinds of switches 415 // Here is where we differentiate between different kinds of switches
422 - h.sw = h.controller.getOFSwitchInstance(drep, h.ofVersion); 416 + h.sw = h.controller.getOFSwitchInstance(h.thisdpid, drep, h.ofVersion);
417 + boolean success = h.sw.addConnectedSwitch();
418 + if (!success) {
419 + disconnectDuplicate(h);
420 + return;
421 + }
423 // set switch information 422 // set switch information
424 h.sw.setOFVersion(h.ofVersion); 423 h.sw.setOFVersion(h.ofVersion);
425 h.sw.setFeaturesReply(h.featuresReply); 424 h.sw.setFeaturesReply(h.featuresReply);
...@@ -433,7 +432,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler { ...@@ -433,7 +432,9 @@ class OFChannelHandler extends IdleStateAwareChannelHandler {
433 //Put switch in EQUAL mode until we hear back from the global registry 432 //Put switch in EQUAL mode until we hear back from the global registry
434 log.debug("Setting new switch {} to EQUAL and sending Role request", 433 log.debug("Setting new switch {} to EQUAL and sending Role request",
435 h.sw.getStringId()); 434 h.sw.getStringId());
436 - h.setSwitchRole(RoleState.EQUAL); 435 + h.sw.addActivatedEqualSwitch();
436 + //h.setSwitchRole(RoleState.EQUAL);
437 + h.setSwitchRole(RoleState.MASTER);
437 h.sw.startDriverHandshake(); 438 h.sw.startDriverHandshake();
438 h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE); 439 h.setState(WAIT_SWITCH_DRIVER_SUB_HANDSHAKE);
439 440
......
...@@ -24,12 +24,19 @@ import org.slf4j.LoggerFactory; ...@@ -24,12 +24,19 @@ import org.slf4j.LoggerFactory;
24 @Service 24 @Service
25 public class OpenFlowControllerImpl implements OpenFlowController { 25 public class OpenFlowControllerImpl implements OpenFlowController {
26 26
27 - protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches; 27 + private static final Logger log =
28 - protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches; 28 + LoggerFactory.getLogger(OpenFlowControllerImpl.class);
29 - protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches; 29 +
30 + protected ConcurrentHashMap<Long, OpenFlowSwitch> connectedSwitches =
31 + new ConcurrentHashMap<Long, OpenFlowSwitch>();
32 + protected ConcurrentHashMap<Long, OpenFlowSwitch> activeMasterSwitches =
33 + new ConcurrentHashMap<Long, OpenFlowSwitch>();
34 + protected ConcurrentHashMap<Long, OpenFlowSwitch> activeEqualSwitches =
35 + new ConcurrentHashMap<Long, OpenFlowSwitch>();
30 36
31 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent(); 37 protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
32 - protected ArrayList<OpenFlowSwitchListener> ofEventListener; 38 + protected ArrayList<OpenFlowSwitchListener> ofEventListener =
39 + new ArrayList<OpenFlowSwitchListener>();
33 40
34 private final Controller ctrl = new Controller(); 41 private final Controller ctrl = new Controller();
35 42
...@@ -98,29 +105,17 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -98,29 +105,17 @@ public class OpenFlowControllerImpl implements OpenFlowController {
98 105
99 @Override 106 @Override
100 public void write(Dpid dpid, OFMessage msg) { 107 public void write(Dpid dpid, OFMessage msg) {
101 - this.getSwitch(dpid).write(msg); 108 + this.getSwitch(dpid).sendMsg(msg);
102 } 109 }
103 110
104 @Override 111 @Override
105 public void processPacket(OFMessage msg) { 112 public void processPacket(OFMessage msg) {
113 + log.info("Got message {}", msg);
106 } 114 }
107 115
108 @Override 116 @Override
109 public void setRole(Dpid dpid, RoleState role) { 117 public void setRole(Dpid dpid, RoleState role) {
110 - switch (role) { 118 + ((AbstractOpenFlowSwitch) getSwitch(dpid)).setRole(role);
111 - case MASTER:
112 - agent.transitionToMasterSwitch(dpid.value());
113 - break;
114 - case EQUAL:
115 - agent.transitionToEqualSwitch(dpid.value());
116 - break;
117 - case SLAVE:
118 - //agent.transitionToSlaveSwitch(dpid.value());
119 - break;
120 - default:
121 - //WTF role is this?
122 - }
123 -
124 } 119 }
125 120
126 public class OpenFlowSwitchAgent { 121 public class OpenFlowSwitchAgent {
...@@ -189,6 +184,7 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -189,6 +184,7 @@ public class OpenFlowControllerImpl implements OpenFlowController {
189 return false; 184 return false;
190 } 185 }
191 activeEqualSwitches.put(dpid, sw); 186 activeEqualSwitches.put(dpid, sw);
187 + log.info("Added Activated EQUAL Switch {}", dpid);
192 return true; 188 return true;
193 } finally { 189 } finally {
194 switchLock.unlock(); 190 switchLock.unlock();
...@@ -203,6 +199,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -203,6 +199,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
203 protected void transitionToMasterSwitch(long dpid) { 199 protected void transitionToMasterSwitch(long dpid) {
204 switchLock.lock(); 200 switchLock.lock();
205 try { 201 try {
202 + if (activeMasterSwitches.containsKey(dpid)) {
203 + return;
204 + }
206 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid); 205 OpenFlowSwitch sw = activeEqualSwitches.remove(dpid);
207 if (sw == null) { 206 if (sw == null) {
208 log.error("Transition to master called on sw {}, but switch " 207 log.error("Transition to master called on sw {}, but switch "
...@@ -224,6 +223,9 @@ public class OpenFlowControllerImpl implements OpenFlowController { ...@@ -224,6 +223,9 @@ public class OpenFlowControllerImpl implements OpenFlowController {
224 protected void transitionToEqualSwitch(long dpid) { 223 protected void transitionToEqualSwitch(long dpid) {
225 switchLock.lock(); 224 switchLock.lock();
226 try { 225 try {
226 + if (activeEqualSwitches.containsKey(dpid)) {
227 + return;
228 + }
227 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid); 229 OpenFlowSwitch sw = activeMasterSwitches.remove(dpid);
228 if (sw == null) { 230 if (sw == null) {
229 log.error("Transition to equal called on sw {}, but switch " 231 log.error("Transition to equal called on sw {}, but switch "
......
...@@ -2,7 +2,6 @@ package org.onlab.onos.of.controller.impl.internal; ...@@ -2,7 +2,6 @@ package org.onlab.onos.of.controller.impl.internal;
2 2
3 import java.io.IOException; 3 import java.io.IOException;
4 import java.util.Collections; 4 import java.util.Collections;
5 -import java.util.concurrent.atomic.AtomicInteger;
6 5
7 import org.onlab.onos.of.controller.RoleState; 6 import org.onlab.onos.of.controller.RoleState;
8 import org.projectfloodlight.openflow.protocol.OFControllerRole; 7 import org.projectfloodlight.openflow.protocol.OFControllerRole;
...@@ -50,7 +49,6 @@ class RoleManager { ...@@ -50,7 +49,6 @@ class RoleManager {
50 49
51 // the expectation set by the caller for the returned role 50 // the expectation set by the caller for the returned role
52 private RoleRecvStatus expectation; 51 private RoleRecvStatus expectation;
53 - private AtomicInteger xidCounter;
54 private AbstractOpenFlowSwitch sw; 52 private AbstractOpenFlowSwitch sw;
55 53
56 54
...@@ -58,7 +56,6 @@ class RoleManager { ...@@ -58,7 +56,6 @@ class RoleManager {
58 this.requestPending = false; 56 this.requestPending = false;
59 this.pendingXid = -1; 57 this.pendingXid = -1;
60 this.pendingRole = null; 58 this.pendingRole = null;
61 - this.xidCounter = new AtomicInteger(0);
62 this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE; 59 this.expectation = RoleRecvStatus.MATCHED_CURRENT_ROLE;
63 this.sw = sw; 60 this.sw = sw;
64 } 61 }
...@@ -85,7 +82,7 @@ class RoleManager { ...@@ -85,7 +82,7 @@ class RoleManager {
85 roleToSend = OFNiciraControllerRole.ROLE_SLAVE; 82 roleToSend = OFNiciraControllerRole.ROLE_SLAVE;
86 log.warn("Sending Nx Role.SLAVE to switch {}.", sw); 83 log.warn("Sending Nx Role.SLAVE to switch {}.", sw);
87 } 84 }
88 - int xid = xidCounter.getAndIncrement(); 85 + int xid = sw.getNextTransactionId();
89 OFExperimenter roleRequest = OFFactories.getFactory(OFVersion.OF_10) 86 OFExperimenter roleRequest = OFFactories.getFactory(OFVersion.OF_10)
90 .buildNiciraControllerRoleRequest() 87 .buildNiciraControllerRoleRequest()
91 .setXid(xid) 88 .setXid(xid)
...@@ -113,7 +110,7 @@ class RoleManager { ...@@ -113,7 +110,7 @@ class RoleManager {
113 + " Should only be used for queries.", sw); 110 + " Should only be used for queries.", sw);
114 } 111 }
115 112
116 - int xid = xidCounter.getAndIncrement(); 113 + int xid = sw.getNextTransactionId();
117 OFRoleRequest rrm = OFFactories.getFactory(OFVersion.OF_13) 114 OFRoleRequest rrm = OFFactories.getFactory(OFVersion.OF_13)
118 .buildRoleRequest() 115 .buildRoleRequest()
119 .setRole(roleToSend) 116 .setRole(roleToSend)
...@@ -121,7 +118,7 @@ class RoleManager { ...@@ -121,7 +118,7 @@ class RoleManager {
121 //FIXME fix below when we actually use generation ids 118 //FIXME fix below when we actually use generation ids
122 .setGenerationId(U64.ZERO) 119 .setGenerationId(U64.ZERO)
123 .build(); 120 .build();
124 - sw.write(rrm); 121 + sw.sendMsg(rrm);
125 return xid; 122 return xid;
126 } 123 }
127 124
......
1 +package org.onlab.onos.of.drivers;
2 +
3 +
4 +import java.util.List;
5 +
6 +import org.onlab.onos.of.controller.Dpid;
7 +import org.onlab.onos.of.controller.RoleState;
8 +import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
9 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
10 +import org.projectfloodlight.openflow.protocol.OFFeaturesReply;
11 +import org.projectfloodlight.openflow.protocol.OFMessage;
12 +import org.projectfloodlight.openflow.protocol.OFVersion;
13 +import org.slf4j.Logger;
14 +import org.slf4j.LoggerFactory;
15 +
16 +/**
17 + * A simple implementation of a driver manager that differentiates between
18 + * connected switches using the OF Description Statistics Reply message.
19 + */
20 +public final class DriverManager {
21 +
22 + private static final Logger log = LoggerFactory.getLogger(DriverManager.class);
23 +
24 + // Whether to use an OF 1.3 configured TTP, or to use an OF 1.0-style
25 + // single table with packet-ins.
26 + private static boolean cpqdUsePipeline13 = false;
27 +
28 + /**
29 + * Return an IOFSwitch object based on switch's manufacturer description
30 + * from OFDescStatsReply.
31 + *
32 + * @param desc DescriptionStatistics reply from the switch
33 + * @return A IOFSwitch instance if the driver found an implementation for
34 + * the given description. Otherwise it returns OFSwitchImplBase
35 + */
36 + public static AbstractOpenFlowSwitch getOFSwitchImpl(Dpid dpid,
37 + OFDescStatsReply desc, OFVersion ofv) {
38 + String vendor = desc.getMfrDesc();
39 + String hw = desc.getHwDesc();
40 + if (vendor.startsWith("Stanford University, Ericsson Research and CPqD Research")
41 + &&
42 + hw.startsWith("OpenFlow 1.3 Reference Userspace Switch")) {
43 + return new OFSwitchImplCPqD13(dpid, desc, cpqdUsePipeline13);
44 + }
45 +
46 + if (vendor.startsWith("Nicira") &&
47 + hw.startsWith("Open vSwitch")) {
48 + if (ofv == OFVersion.OF_10) {
49 + return new OFSwitchImplOVS10(dpid, desc);
50 + } else if (ofv == OFVersion.OF_13) {
51 + return new OFSwitchImplOVS13(dpid, desc);
52 + }
53 + }
54 +
55 + log.warn("DriverManager could not identify switch desc: {}. "
56 + + "Assigning OFSwitchImplBase", desc);
57 + AbstractOpenFlowSwitch base = new AbstractOpenFlowSwitch(dpid) {
58 +
59 + @Override
60 + public void write(List<OFMessage> msgs) {
61 + // TODO Auto-generated method stub
62 + }
63 +
64 + @Override
65 + public void sendMsg(OFMessage m) {
66 + // TODO Auto-generated method stub
67 + }
68 +
69 + @Override
70 + public Boolean supportNxRole() {
71 + // TODO Auto-generated method stub
72 + return null;
73 + }
74 +
75 + @Override
76 + public void startDriverHandshake() {
77 + // TODO Auto-generated method stub
78 + }
79 +
80 + @Override
81 + public void setFeaturesReply(OFFeaturesReply featuresReply) {
82 + // TODO Auto-generated method stub
83 +
84 + }
85 +
86 + @Override
87 + public void processDriverHandshakeMessage(OFMessage m) {
88 + // TODO Auto-generated method stub
89 + }
90 +
91 + @Override
92 + public boolean isDriverHandshakeComplete() {
93 + // TODO Auto-generated method stub
94 + return false;
95 + }
96 +
97 + @Override
98 + public RoleState getRole() {
99 + // TODO Auto-generated method stub
100 + return null;
101 + }
102 + };
103 + base.setSwitchDescription(desc);
104 + // XXX S must set counter here - unidentified switch
105 + return base;
106 + }
107 +
108 + /**
109 + * Private constructor to avoid instantiation.
110 + */
111 + private DriverManager() {
112 + }
113 +
114 + /**
115 + * Sets the configuration parameter which determines how the CPqD switch
116 + * is set up. If usePipeline13 is true, a 1.3 pipeline will be set up on
117 + * the switch. Otherwise, the switch will be set up in a 1.0 style with
118 + * a single table where missed packets are sent to the controller.
119 + *
120 + * @param usePipeline13 whether to use a 1.3 pipeline or not
121 + */
122 + public static void setConfigForCpqd(boolean usePipeline13) {
123 + cpqdUsePipeline13 = usePipeline13;
124 + }
125 +}
1 +package org.onlab.onos.of.drivers;
2 +
3 +import java.io.IOException;
4 +import java.util.ArrayList;
5 +import java.util.Collections;
6 +import java.util.List;
7 +import java.util.concurrent.ConcurrentHashMap;
8 +import java.util.concurrent.atomic.AtomicBoolean;
9 +
10 +import org.onlab.onos.of.controller.Dpid;
11 +import org.onlab.onos.of.controller.RoleState;
12 +import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
13 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted;
14 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted;
15 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted;
16 +import org.projectfloodlight.openflow.protocol.OFAsyncGetReply;
17 +import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
18 +import org.projectfloodlight.openflow.protocol.OFBucket;
19 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
20 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
21 +import org.projectfloodlight.openflow.protocol.OFFactory;
22 +import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply;
23 +import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply;
24 +import org.projectfloodlight.openflow.protocol.OFGroupType;
25 +import org.projectfloodlight.openflow.protocol.OFMatchV3;
26 +import org.projectfloodlight.openflow.protocol.OFMessage;
27 +import org.projectfloodlight.openflow.protocol.OFOxmList;
28 +import org.projectfloodlight.openflow.protocol.OFPortDesc;
29 +import org.projectfloodlight.openflow.protocol.OFStatsReply;
30 +import org.projectfloodlight.openflow.protocol.action.OFAction;
31 +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
32 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthDst;
33 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthSrc;
34 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType;
35 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort;
36 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmIpv4DstMasked;
37 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmMetadataMasked;
38 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmMplsLabel;
39 +import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid;
40 +import org.projectfloodlight.openflow.types.EthType;
41 +import org.projectfloodlight.openflow.types.IPv4Address;
42 +import org.projectfloodlight.openflow.types.MacAddress;
43 +import org.projectfloodlight.openflow.types.OFBufferId;
44 +import org.projectfloodlight.openflow.types.OFGroup;
45 +import org.projectfloodlight.openflow.types.OFMetadata;
46 +import org.projectfloodlight.openflow.types.OFPort;
47 +import org.projectfloodlight.openflow.types.OFVlanVidMatch;
48 +import org.projectfloodlight.openflow.types.TableId;
49 +import org.projectfloodlight.openflow.types.U32;
50 +import org.projectfloodlight.openflow.types.U64;
51 +import org.projectfloodlight.openflow.util.HexString;
52 +import org.slf4j.Logger;
53 +import org.slf4j.LoggerFactory;
54 +
55 +/**
56 + * OFDescriptionStatistics Vendor (Manufacturer Desc.): Stanford University,
57 + * Ericsson Research and CPqD Research. Make (Hardware Desc.) : OpenFlow 1.3
58 + * Reference Userspace Switch Model (Datapath Desc.) : None Software : Serial :
59 + * None
60 + */
61 +public class OFSwitchImplCPqD13 extends AbstractOpenFlowSwitch {
62 +
63 + private static Logger log =
64 + LoggerFactory.getLogger(OFSwitchImplCPqD13.class);
65 +
66 + private static final int VLAN_ID_OFFSET = 16;
67 + private AtomicBoolean driverHandshakeComplete;
68 + private OFFactory factory;
69 + private static final int OFPCML_NO_BUFFER = 0xffff;
70 + // Configuration of asynch messages to controller. We need different
71 + // asynch messages depending on role-equal or role-master.
72 + // We don't want to get anything if we are slave.
73 + private static final long SET_FLOW_REMOVED_MASK_MASTER = 0xf;
74 + private static final long SET_PACKET_IN_MASK_MASTER = 0x7;
75 + private static final long SET_PORT_STATUS_MASK_MASTER = 0x7;
76 + private static final long SET_FLOW_REMOVED_MASK_EQUAL = 0x0;
77 + private static final long SET_PACKET_IN_MASK_EQUAL = 0x0;
78 + private static final long SET_PORT_STATUS_MASK_EQUAL = 0x7;
79 + private static final long SET_ALL_SLAVE = 0x0;
80 +
81 + private static final long TEST_FLOW_REMOVED_MASK = 0xf;
82 + private static final long TEST_PACKET_IN_MASK = 0x7;
83 + private static final long TEST_PORT_STATUS_MASK = 0x7;
84 + private long barrierXidToWaitFor = -1;
85 +
86 + private static final int TABLE_VLAN = 0;
87 + private static final int TABLE_TMAC = 1;
88 + private static final int TABLE_IPV4_UNICAST = 2;
89 + private static final int TABLE_MPLS = 3;
90 + private static final int TABLE_META = 4;
91 + private static final int TABLE_ACL = 5;
92 +
93 + private static final short MAX_PRIORITY = (short) 0xffff;
94 + private static final short SLASH_24_PRIORITY = (short) 0xfff0;
95 + private static final short MIN_PRIORITY = 0x0;
96 + private static final U64 METADATA_MASK = U64.of(Long.MAX_VALUE << 1 | 0x1);
97 +
98 + ConcurrentHashMap<Integer, OFGroup> l2groups;
99 +
100 + private final boolean usePipeline13;
101 +
102 + public OFSwitchImplCPqD13(Dpid dpid, OFDescStatsReply desc, boolean usePipeline13) {
103 + super(dpid);
104 + driverHandshakeComplete = new AtomicBoolean(false);
105 + l2groups = new ConcurrentHashMap<Integer, OFGroup>();
106 + setSwitchDescription(desc);
107 +
108 + this.usePipeline13 = usePipeline13;
109 + }
110 +
111 + /* (non-Javadoc)
112 + * @see java.lang.Object#toString()
113 + */
114 + @Override
115 + public String toString() {
116 + return "OFSwitchImplCPqD13 [" + ((channel != null)
117 + ? channel.getRemoteAddress() : "?")
118 + + " DPID[" + ((this.getStringId() != null) ? this.getStringId() : "?") + "]]";
119 + }
120 +
121 + @Override
122 + public void startDriverHandshake() {
123 + log.debug("Starting driver handshake for sw {}", getStringId());
124 + if (startDriverHandshakeCalled) {
125 + throw new SwitchDriverSubHandshakeAlreadyStarted();
126 + }
127 + startDriverHandshakeCalled = true;
128 + factory = this.factory();
129 + if (!usePipeline13) {
130 + // Send packet-in to controller if a packet misses the first table
131 + populateTableMissEntry(0, true, false, false, 0);
132 + } //else {
133 + // configureSwitch();
134 + //}
135 + sendBarrier(true);
136 + }
137 +
138 + @Override
139 + public boolean isDriverHandshakeComplete() {
140 + if (!startDriverHandshakeCalled) {
141 + throw new SwitchDriverSubHandshakeNotStarted();
142 + }
143 + return driverHandshakeComplete.get();
144 + }
145 +
146 + @Override
147 + public void processDriverHandshakeMessage(OFMessage m) {
148 + if (!startDriverHandshakeCalled) {
149 + throw new SwitchDriverSubHandshakeNotStarted();
150 + }
151 + if (driverHandshakeComplete.get()) {
152 + throw new SwitchDriverSubHandshakeCompleted(m);
153 + }
154 +
155 + if (!startDriverHandshakeCalled) {
156 + throw new SwitchDriverSubHandshakeNotStarted();
157 + }
158 + if (driverHandshakeComplete.get()) {
159 + throw new SwitchDriverSubHandshakeCompleted(m);
160 + }
161 +
162 + switch (m.getType()) {
163 + case BARRIER_REPLY:
164 + if (m.getXid() == barrierXidToWaitFor) {
165 + driverHandshakeComplete.set(true);
166 + }
167 + break;
168 +
169 + case ERROR:
170 + log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
171 + break;
172 +
173 + case FEATURES_REPLY:
174 + break;
175 + case FLOW_REMOVED:
176 + break;
177 + case GET_ASYNC_REPLY:
178 + OFAsyncGetReply asrep = (OFAsyncGetReply) m;
179 + decodeAsyncGetReply(asrep);
180 + break;
181 +
182 + case PACKET_IN:
183 + break;
184 + case PORT_STATUS:
185 + break;
186 + case QUEUE_GET_CONFIG_REPLY:
187 + break;
188 + case ROLE_REPLY:
189 + break;
190 +
191 + case STATS_REPLY:
192 + processStatsReply((OFStatsReply) m);
193 + break;
194 +
195 + default:
196 + log.debug("Received message {} during switch-driver subhandshake "
197 + + "from switch {} ... Ignoring message", m, getStringId());
198 +
199 + }
200 + }
201 +
202 + private void configureSwitch() throws IOException {
203 + // setAsyncConfig();
204 + // getTableFeatures();
205 + sendGroupFeaturesRequest();
206 + setL2Groups();
207 + sendBarrier(false);
208 + setL3Groups();
209 + setL25Groups();
210 + sendGroupDescRequest();
211 + populateTableVlan();
212 + populateTableTMac();
213 + populateIpTable();
214 + populateMplsTable();
215 + populateTableMissEntry(TABLE_ACL, false, false, false, -1);
216 + sendBarrier(true);
217 + }
218 +
219 + private void setAsyncConfig() throws IOException {
220 + List<OFMessage> msglist = new ArrayList<OFMessage>(3);
221 + OFMessage setAC = null;
222 +
223 + if (role == RoleState.MASTER) {
224 + setAC = factory.buildAsyncSet()
225 + .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_MASTER)
226 + .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_MASTER)
227 + .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_MASTER)
228 + .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
229 + .setPacketInMaskSlave(SET_ALL_SLAVE)
230 + .setPortStatusMaskSlave(SET_ALL_SLAVE)
231 + .setXid(getNextTransactionId())
232 + .build();
233 + } else if (role == RoleState.EQUAL) {
234 + setAC = factory.buildAsyncSet()
235 + .setFlowRemovedMaskEqualMaster(SET_FLOW_REMOVED_MASK_EQUAL)
236 + .setPacketInMaskEqualMaster(SET_PACKET_IN_MASK_EQUAL)
237 + .setPortStatusMaskEqualMaster(SET_PORT_STATUS_MASK_EQUAL)
238 + .setFlowRemovedMaskSlave(SET_ALL_SLAVE)
239 + .setPacketInMaskSlave(SET_ALL_SLAVE)
240 + .setPortStatusMaskSlave(SET_ALL_SLAVE)
241 + .setXid(getNextTransactionId())
242 + .build();
243 + }
244 + msglist.add(setAC);
245 +
246 + OFMessage br = factory.buildBarrierRequest()
247 + .setXid(getNextTransactionId())
248 + .build();
249 + msglist.add(br);
250 +
251 + OFMessage getAC = factory.buildAsyncGetRequest()
252 + .setXid(getNextTransactionId())
253 + .build();
254 + msglist.add(getAC);
255 +
256 + write(msglist);
257 + }
258 +
259 + private void decodeAsyncGetReply(OFAsyncGetReply rep) {
260 + long frm = rep.getFlowRemovedMaskEqualMaster();
261 + //long frs = rep.getFlowRemovedMaskSlave();
262 + long pim = rep.getPacketInMaskEqualMaster();
263 + //long pis = rep.getPacketInMaskSlave();
264 + long psm = rep.getPortStatusMaskEqualMaster();
265 + //long pss = rep.getPortStatusMaskSlave();
266 +
267 + if (role == RoleState.MASTER || role == RoleState.EQUAL) { // should separate
268 + log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK)));
269 + log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK)));
270 + log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK)));
271 + }
272 +
273 + }
274 +
275 + private void getTableFeatures() throws IOException {
276 + OFMessage gtf = factory.buildTableFeaturesStatsRequest()
277 + .setXid(getNextTransactionId())
278 + .build();
279 + sendMsg(gtf);
280 + }
281 +
282 + private void sendGroupFeaturesRequest() throws IOException {
283 + OFMessage gfr = factory.buildGroupFeaturesStatsRequest()
284 + .setXid(getNextTransactionId())
285 + .build();
286 + sendMsg(gfr);
287 + }
288 +
289 + private void sendGroupDescRequest() throws IOException {
290 + OFMessage gdr = factory.buildGroupDescStatsRequest()
291 + .setXid(getNextTransactionId())
292 + .build();
293 + sendMsg(gdr);
294 + }
295 +
296 + /*Create L2 interface groups for all physical ports
297 + Naming convention followed is the same as OF-DPA spec
298 + eg. port 1 with allowed vlan 10, is enveloped in group with id,
299 + 0x0 00a 0001, where the uppermost 4 bits identify an L2 interface,
300 + the next 12 bits identify the vlan-id, and the lowermost 16 bits
301 + identify the port number.*/
302 + private void setL2Groups() throws IOException {
303 + List<OFMessage> msglist = new ArrayList<OFMessage>();
304 + for (OFPortDesc p : getPorts()) {
305 + int pnum = p.getPortNo().getPortNumber();
306 + int portVlan = getVlanConfig(pnum);
307 + if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
308 + OFGroup gl2 = OFGroup.of(pnum | (portVlan << VLAN_ID_OFFSET));
309 + OFAction out = factory.actions().buildOutput()
310 + .setPort(p.getPortNo()).build();
311 + OFAction popVlan = factory.actions().popVlan();
312 + List<OFAction> actions = new ArrayList<OFAction>();
313 + actions.add(popVlan);
314 + actions.add(out);
315 + OFBucket bucket = factory.buildBucket()
316 + .setActions(actions).build();
317 + List<OFBucket> buckets = Collections.singletonList(bucket);
318 + OFMessage gmAdd = factory.buildGroupAdd()
319 + .setGroup(gl2)
320 + .setBuckets(buckets)
321 + .setGroupType(OFGroupType.INDIRECT)
322 + .setXid(getNextTransactionId())
323 + .build();
324 + msglist.add(gmAdd);
325 + l2groups.put(pnum, gl2);
326 + }
327 + }
328 + log.debug("Creating {} L2 groups in sw {}", msglist.size(), getStringId());
329 + write(msglist);
330 + }
331 +
332 + private int getVlanConfig(int portnum) {
333 + int portVlan = 10 * portnum;
334 + if ((getId() == 0x1 && portnum == 6) ||
335 + (getId() == 0x2) ||
336 + (getId() == 0x3 && portnum == 2)) {
337 + portVlan = 192; // 0xc0
338 + }
339 + return portVlan;
340 + }
341 +
342 + private MacAddress getRouterMacAddr() {
343 + if (getId() == 0x3) {
344 + return MacAddress.of("00:00:07:07:07:80"); // router mac
345 + }
346 + if (getId() == 0x1) {
347 + return MacAddress.of("00:00:01:01:01:80");
348 + }
349 + // switch 0x2
350 + return MacAddress.of("00:00:02:02:02:80");
351 + }
352 +
353 + // only for ports connected to other routers
354 + private OFAction getDestAction(int portnum) {
355 + OFAction setDA = null;
356 + MacAddress dAddr = null;
357 + if (getId() == 0x1 && portnum == 6) { // connected to switch 2
358 + dAddr = MacAddress.of("00:00:02:02:02:80");
359 + }
360 + if (getId() == 0x2) {
361 + if (portnum == 1) { // connected to sw 1
362 + dAddr = MacAddress.of("00:00:01:01:01:80");
363 + } else if (portnum == 2) { // connected to sw 3
364 + dAddr = MacAddress.of("00:00:07:07:07:80");
365 + }
366 + }
367 + if (getId() == 0x3) {
368 + if (portnum == 2) { // connected to switch 2
369 + dAddr = MacAddress.of("00:00:02:02:02:80");
370 + }
371 + }
372 +
373 + if (dAddr != null) {
374 + OFOxmEthDst dstAddr = factory.oxms().ethDst(dAddr);
375 + setDA = factory.actions().buildSetField()
376 + .setField(dstAddr).build();
377 + }
378 + return setDA;
379 + }
380 +
381 + /*
382 + * L3 groups are created for all router ports and they all point to corresponding
383 + * L2 groups. Only the ports that connect to other routers will have the
384 + * DA set.
385 + */
386 + private void setL3Groups() throws IOException {
387 + List<OFMessage> msglist = new ArrayList<OFMessage>();
388 + for (OFGroup gl2 : l2groups.values()) {
389 + int gnum = gl2.getGroupNumber();
390 + int portnum = gnum & 0x0000ffff;
391 + int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
392 + MacAddress sAddr = getRouterMacAddr();
393 +
394 + OFGroup gl3 = OFGroup.of(0x20000000 | portnum);
395 + OFAction group = factory.actions().buildGroup()
396 + .setGroup(gl2).build();
397 + OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
398 + OFAction setSA = factory.actions().buildSetField()
399 + .setField(srcAddr).build();
400 + OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
401 + OFAction setVlan = factory.actions().buildSetField()
402 + .setField(vid).build();
403 + OFAction decTtl = factory.actions().decNwTtl();
404 +
405 + List<OFAction> actions = new ArrayList<OFAction>();
406 + actions.add(decTtl); // decrement the IP TTL/do-checksum/check TTL
407 + // and MTU
408 + actions.add(setVlan); // set the vlan-id of the exit-port (and
409 + // l2group)
410 + actions.add(setSA); // set this routers mac address
411 + // make L3Unicast group setDA for known (configured) ports
412 + // that connect to other routers
413 + OFAction setDA = getDestAction(portnum);
414 + if (setDA != null) {
415 + actions.add(setDA);
416 + }
417 + actions.add(group);
418 +
419 + OFBucket bucket = factory.buildBucket()
420 + .setActions(actions).build();
421 + List<OFBucket> buckets = Collections.singletonList(bucket);
422 + OFMessage gmAdd = factory.buildGroupAdd()
423 + .setGroup(gl3)
424 + .setBuckets(buckets)
425 + .setGroupType(OFGroupType.INDIRECT)
426 + .setXid(getNextTransactionId())
427 + .build();
428 + msglist.add(gmAdd);
429 + }
430 + write(msglist);
431 + log.debug("Creating {} L3 groups in sw {}", msglist.size(), getStringId());
432 + }
433 +
434 + /*
435 + * L2.5 or mpls-unicast groups are only created for those router ports
436 + * connected to other router ports. They differ from the corresponding
437 + * L3-unicast group only by the fact that they decrement the MPLS TTL
438 + * instead of the IP ttl
439 + */
440 + private void setL25Groups() throws IOException {
441 + List<OFMessage> msglist = new ArrayList<OFMessage>();
442 + for (OFGroup gl2 : l2groups.values()) {
443 + int gnum = gl2.getGroupNumber();
444 + int portnum = gnum & 0x0000ffff;
445 + int vlanid = ((gnum & 0x0fff0000) >> VLAN_ID_OFFSET);
446 + MacAddress sAddr = getRouterMacAddr();
447 + OFAction setDA = getDestAction(portnum);
448 + // setDA will only be non-null for ports connected to routers
449 + if (setDA != null) {
450 + OFGroup gl3 = OFGroup.of(0xa0000000 | portnum); // different id
451 + // for mpls
452 + // group
453 + OFAction group = factory.actions().buildGroup()
454 + .setGroup(gl2).build();
455 + OFOxmEthSrc srcAddr = factory.oxms().ethSrc(sAddr);
456 + OFAction setSA = factory.actions().buildSetField()
457 + .setField(srcAddr).build();
458 + OFOxmVlanVid vid = factory.oxms().vlanVid(OFVlanVidMatch.ofVlan(vlanid));
459 + OFAction setVlan = factory.actions().buildSetField()
460 + .setField(vid).build();
461 + OFAction decMplsTtl = factory.actions().decMplsTtl();
462 + List<OFAction> actions = new ArrayList<OFAction>();
463 + actions.add(decMplsTtl); // decrement the MPLS
464 + // TTL/do-checksum/check TTL and MTU
465 + actions.add(setVlan); // set the vlan-id of the exit-port (and
466 + // l2group)
467 + actions.add(setSA); // set this routers mac address
468 + actions.add(setDA);
469 + actions.add(group);
470 + OFBucket bucket = factory.buildBucket()
471 + .setActions(actions).build();
472 + List<OFBucket> buckets = Collections.singletonList(bucket);
473 + OFMessage gmAdd = factory.buildGroupAdd()
474 + .setGroup(gl3)
475 + .setBuckets(buckets)
476 + .setGroupType(OFGroupType.INDIRECT)
477 + .setXid(getNextTransactionId())
478 + .build();
479 + msglist.add(gmAdd);
480 + }
481 + }
482 + write(msglist);
483 + log.debug("Creating {} MPLS groups in sw {}", msglist.size(), getStringId());
484 + }
485 +
486 + /* Using ECMP groups
487 + *
488 + * OFGroup group47 = OFGroup.of(47);
489 + OFAction outgroup1 = factory.actions()
490 + .buildGroup()
491 + .setGroup(group61)
492 + .build();
493 + OFBucket buc47_1 = factory.buildBucket()
494 + .setWeight(1)
495 + .setActions(Collections.singletonList(outgroup1))
496 + .build();
497 + OFAction outgroup2 = factory.actions()
498 + .buildGroup()
499 + .setGroup(group62)
500 + .build();
501 + OFBucket buc47_2 = factory.buildBucket()
502 + .setWeight(1)
503 + .setActions(Collections.singletonList(outgroup2))
504 + .build();
505 + List<OFBucket> buckets47 = new ArrayList<OFBucket>();
506 + buckets47.add(buc47_1);
507 + buckets47.add(buc47_2);
508 + OFMessage gmS12 = factory.buildGroupAdd()
509 + .setGroup(group47)
510 + .setBuckets(buckets47)
511 + .setGroupType(OFGroupType.SELECT)
512 + .setXid(getNextTransactionId())
513 + .build();
514 + write(gmS12, null); */
515 +
516 + private void processStatsReply(OFStatsReply sr) {
517 + switch (sr.getStatsType()) {
518 + case AGGREGATE:
519 + break;
520 + case DESC:
521 + break;
522 + case EXPERIMENTER:
523 + break;
524 + case FLOW:
525 + break;
526 + case GROUP_DESC:
527 + processGroupDesc((OFGroupDescStatsReply) sr);
528 + break;
529 + case GROUP_FEATURES:
530 + processGroupFeatures((OFGroupFeaturesStatsReply) sr);
531 + break;
532 + case METER_CONFIG:
533 + break;
534 + case METER_FEATURES:
535 + break;
536 + case PORT_DESC:
537 + break;
538 + case TABLE_FEATURES:
539 + break;
540 + default:
541 + break;
542 +
543 + }
544 + }
545 +
546 + private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) {
547 + log.info("Sw: {} Group Features {}", getStringId(), gfsr);
548 + }
549 +
550 + private void processGroupDesc(OFGroupDescStatsReply gdsr) {
551 + log.info("Sw: {} Group Desc {}", getStringId(), gdsr);
552 + }
553 +
554 + private void populateTableVlan() throws IOException {
555 + // for all incoming ports assign configured port-vlans
556 + // currently assign portnum*10 -> vlanid to access ports
557 + // and vlan 192 to router to router ports
558 + List<OFMessage> msglist = new ArrayList<OFMessage>();
559 + for (OFPortDesc p : getPorts()) {
560 + int pnum = p.getPortNo().getPortNumber();
561 + if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) {
562 + int vlanid = getVlanConfig(pnum);
563 + OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo());
564 + OFOxmVlanVid oxv = factory.oxms()
565 + .vlanVid(OFVlanVidMatch.UNTAGGED);
566 + OFOxmList oxmList = OFOxmList.of(oxp, oxv);
567 + OFMatchV3 match = factory.buildMatchV3()
568 + .setOxmList(oxmList).build();
569 + OFOxmVlanVid vidToSet = factory.oxms()
570 + .vlanVid(OFVlanVidMatch.ofVlan(vlanid));
571 + OFAction pushVlan = factory.actions().pushVlan(EthType.VLAN_FRAME);
572 + OFAction setVlan = factory.actions().setField(vidToSet);
573 + List<OFAction> actionlist = new ArrayList<OFAction>();
574 + actionlist.add(pushVlan);
575 + actionlist.add(setVlan);
576 + OFInstruction appAction = factory.instructions().buildApplyActions()
577 + .setActions(actionlist).build();
578 + OFInstruction gotoTbl = factory.instructions().buildGotoTable()
579 + .setTableId(TableId.of(TABLE_TMAC)).build();
580 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
581 + instructions.add(appAction);
582 + instructions.add(gotoTbl);
583 + OFMessage flowEntry = factory.buildFlowAdd()
584 + .setTableId(TableId.of(TABLE_VLAN))
585 + .setMatch(match)
586 + .setInstructions(instructions)
587 + .setPriority(1000) // does not matter - all rules
588 + // exclusive
589 + .setBufferId(OFBufferId.NO_BUFFER)
590 + .setIdleTimeout(0)
591 + .setHardTimeout(0)
592 + .setXid(getNextTransactionId())
593 + .build();
594 + msglist.add(flowEntry);
595 + }
596 + }
597 + // table-vlan has no table-miss entry, and so packets that miss are
598 + // essentially dropped
599 + write(msglist);
600 + log.debug("Adding {} vlan-rules in sw {}", msglist.size(), getStringId());
601 + }
602 +
603 + private void populateTableTMac() throws IOException {
604 + // match for ip packets
605 + OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4);
606 + OFOxmList oxmListIp = OFOxmList.of(oxe);
607 + OFMatchV3 matchIp = factory.buildMatchV3()
608 + .setOxmList(oxmListIp).build();
609 + OFInstruction gotoTblIp = factory.instructions().buildGotoTable()
610 + .setTableId(TableId.of(TABLE_IPV4_UNICAST)).build();
611 + List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp);
612 + OFMessage ipEntry = factory.buildFlowAdd()
613 + .setTableId(TableId.of(TABLE_TMAC))
614 + .setMatch(matchIp)
615 + .setInstructions(instructionsIp)
616 + .setPriority(1000) // strict priority required lower than
617 + // multicastMac
618 + .setBufferId(OFBufferId.NO_BUFFER)
619 + .setIdleTimeout(0)
620 + .setHardTimeout(0)
621 + .setXid(getNextTransactionId())
622 + .build();
623 +
624 + // match for mpls packets
625 + OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST);
626 + OFOxmList oxmListMpls = OFOxmList.of(oxmpls);
627 + OFMatchV3 matchMpls = factory.buildMatchV3()
628 + .setOxmList(oxmListMpls).build();
629 + OFInstruction gotoTblMpls = factory.instructions().buildGotoTable()
630 + .setTableId(TableId.of(TABLE_MPLS)).build();
631 + List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls);
632 + OFMessage mplsEntry = factory.buildFlowAdd()
633 + .setTableId(TableId.of(TABLE_TMAC))
634 + .setMatch(matchMpls)
635 + .setInstructions(instructionsMpls)
636 + .setPriority(1001) // strict priority required lower than
637 + // multicastMac
638 + .setBufferId(OFBufferId.NO_BUFFER)
639 + .setIdleTimeout(0)
640 + .setHardTimeout(0)
641 + .setXid(getNextTransactionId())
642 + .build();
643 +
644 + // match for everything else to send to controller. Essentially
645 + // the table miss flow entry
646 + populateTableMissEntry(TABLE_TMAC, true, false, false, -1);
647 + log.debug("Adding termination-mac-rules in sw {}", getStringId());
648 + List<OFMessage> msglist = new ArrayList<OFMessage>(2);
649 + msglist.add(ipEntry);
650 + msglist.add(mplsEntry);
651 + write(msglist);
652 + }
653 +
654 + private List<String> getMyIps() { // send to controller
655 + List<String> myIps = new ArrayList<String>();
656 + if (getId() == 0x1) {
657 + myIps.add("10.0.2.128");
658 + myIps.add("10.0.3.128");
659 + myIps.add("10.0.1.128");
660 + myIps.add("192.168.0.1");
661 + }
662 + if (getId() == 0x2) {
663 + myIps.add("192.168.0.2");
664 + }
665 + if (getId() == 0x3) {
666 + myIps.add("192.168.0.3");
667 + myIps.add("7.7.7.128");
668 + }
669 + return myIps;
670 + }
671 +
672 + private List<String> getMySubnetIps() { // send to controller
673 + List<String> subnetIps = new ArrayList<String>();
674 + if (getId() == 0x1) {
675 + subnetIps.add("10.0.2.0");
676 + subnetIps.add("10.0.3.0");
677 + subnetIps.add("10.0.1.0");
678 + }
679 + // TODO needed?
680 + //if (getId() == 0x2) {
681 + //}
682 + if (getId() == 0x3) {
683 + subnetIps.add("7.7.7.0");
684 + }
685 + return subnetIps;
686 + }
687 +
688 + private static class RouteEntry {
689 + String prefix;
690 + String mask;
691 + int nextHopPort;
692 + String dstMac;
693 + int label;
694 +
695 + public RouteEntry(String prefix, String mask, int nextHopPort, int label) {
696 + this.prefix = prefix;
697 + this.mask = mask;
698 + this.nextHopPort = nextHopPort;
699 + this.label = label;
700 + }
701 +
702 + public RouteEntry(String prefix, int nextHopPort, String dstMac) {
703 + this.prefix = prefix;
704 + this.nextHopPort = nextHopPort;
705 + this.dstMac = dstMac;
706 + }
707 + }
708 +
709 + // send out of mpls-group where the next-hop mac-da is already set
710 + private List<RouteEntry> getRouterNextHopIps() {
711 + List<RouteEntry> routerNextHopIps = new ArrayList<RouteEntry>();
712 + if (getId() == 0x1) {
713 + routerNextHopIps
714 + .add(new RouteEntry("192.168.0.2", "255.255.255.255", 6, 102));
715 + routerNextHopIps
716 + .add(new RouteEntry("192.168.0.3", "255.255.255.255", 6, 103));
717 + routerNextHopIps.add(new RouteEntry("7.7.7.0", "255.255.255.0", 6, 103));
718 + }
719 + //if (getId() == 0x2) {
720 + /* These are required for normal IP routing without labels.
721 + routerNextHopIps.add(new RouteEntry("192.168.0.1","255.255.255.255",1));
722 + routerNextHopIps.add(new RouteEntry("192.168.0.3","255.255.255.255",2));
723 + routerNextHopIps.add(new RouteEntry("10.0.1.0","255.255.255.0",1));
724 + routerNextHopIps.add(new RouteEntry("10.0.2.0","255.255.255.0",1));
725 + routerNextHopIps.add(new RouteEntry("10.0.3.0","255.255.255.0",1));
726 + routerNextHopIps.add(new RouteEntry("7.7.7.0","255.255.255.0",2));*/
727 + //}
728 + if (getId() == 0x3) {
729 + routerNextHopIps
730 + .add(new RouteEntry("192.168.0.2", "255.255.255.255", 2, 102));
731 + routerNextHopIps
732 + .add(new RouteEntry("192.168.0.1", "255.255.255.255", 2, 101));
733 + routerNextHopIps.add(new RouteEntry("10.0.1.0", "255.255.255.0", 2, 101));
734 + routerNextHopIps.add(new RouteEntry("10.0.2.0", "255.255.255.0", 2, 101));
735 + routerNextHopIps.add(new RouteEntry("10.0.3.0", "255.255.255.0", 2, 101));
736 + }
737 + return routerNextHopIps;
738 + }
739 +
740 + // known host mac-addr, setDA/send out of l3group
741 + private List<RouteEntry> getHostNextHopIps() {
742 + List<RouteEntry> hostNextHopIps = new ArrayList<RouteEntry>();
743 + if (getId() == 0x1) {
744 + hostNextHopIps.add(new RouteEntry("10.0.2.1", 4, "00:00:00:00:02:01"));
745 + hostNextHopIps.add(new RouteEntry("10.0.3.1", 5, "00:00:00:00:03:01"));
746 + }
747 + // TODO needed?
748 + //if (getId() == 0x2) {
749 + //}
750 + if (getId() == 0x3) {
751 + hostNextHopIps.add(new RouteEntry("7.7.7.7", 1, "00:00:07:07:07:07"));
752 + }
753 + return hostNextHopIps;
754 + }
755 +
756 + private void populateIpTable() throws IOException {
757 + populateMyIps();
758 + populateMySubnets();
759 + populateRoutes();
760 + populateHostRoutes();
761 +
762 + // match for everything else to send to ACL table. Essentially
763 + // the table miss flow entry
764 + populateTableMissEntry(TABLE_IPV4_UNICAST, false, true,
765 + true, TABLE_ACL);
766 + }
767 +
768 + private void populateMyIps() throws IOException {
769 + List<OFMessage> msglist = new ArrayList<OFMessage>();
770 + // first all my ip's as exact-matches
771 + // write-action instruction to send to controller
772 + List<String> myIps = getMyIps();
773 + for (int i = 0; i < myIps.size(); i++) {
774 + OFOxmEthType ethTypeIp = factory.oxms()
775 + .ethType(EthType.IPv4);
776 + OFOxmIpv4DstMasked ipPrefix = factory.oxms()
777 + .ipv4DstMasked(IPv4Address.of(myIps.get(i)), IPv4Address.NO_MASK);
778 + OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
779 + OFMatchV3 match = factory.buildMatchV3()
780 + .setOxmList(oxmListSlash32).build();
781 + OFAction outc = factory.actions().buildOutput()
782 + .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
783 + .build();
784 + OFInstruction writeInstr = factory.instructions().buildWriteActions()
785 + .setActions(Collections.singletonList(outc)).build();
786 + OFInstruction gotoInstr = factory.instructions().buildGotoTable()
787 + .setTableId(TableId.of(TABLE_ACL)).build();
788 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
789 + instructions.add(writeInstr);
790 + instructions.add(gotoInstr);
791 + OFMessage myIpEntry = factory.buildFlowAdd()
792 + .setTableId(TableId.of(TABLE_IPV4_UNICAST))
793 + .setMatch(match)
794 + .setInstructions(instructions)
795 + .setPriority(MAX_PRIORITY) // highest priority for exact
796 + // match
797 + .setBufferId(OFBufferId.NO_BUFFER)
798 + .setIdleTimeout(0)
799 + .setHardTimeout(0)
800 + .setXid(getNextTransactionId())
801 + .build();
802 + msglist.add(myIpEntry);
803 + }
804 + write(msglist);
805 + log.debug("Adding {} my-ip-rules in sw {}", msglist.size(), getStringId());
806 + }
807 +
808 + private void populateMySubnets() throws IOException {
809 + List<OFMessage> msglist = new ArrayList<OFMessage>();
810 + // next prefix-based subnet-IP's configured on my interfaces
811 + // need to ARP for exact-IP, so write-action instruction to send to
812 + // controller
813 + // this has different mask and priority than earlier case
814 + List<String> subnetIps = getMySubnetIps();
815 + for (int i = 0; i < subnetIps.size(); i++) {
816 + OFOxmEthType ethTypeIp = factory.oxms()
817 + .ethType(EthType.IPv4);
818 + OFOxmIpv4DstMasked ipPrefix = factory.oxms().ipv4DstMasked(
819 + IPv4Address.of(subnetIps.get(i)),
820 + IPv4Address.of(0xffffff00)); // '/24' mask
821 + OFOxmList oxmListSlash24 = OFOxmList.of(ethTypeIp, ipPrefix);
822 + OFMatchV3 match = factory.buildMatchV3()
823 + .setOxmList(oxmListSlash24).build();
824 + OFAction outc = factory.actions().buildOutput()
825 + .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
826 + .build();
827 + OFInstruction writeInstr = factory.instructions().buildWriteActions()
828 + .setActions(Collections.singletonList(outc)).build();
829 + OFInstruction gotoInstr = factory.instructions().buildGotoTable()
830 + .setTableId(TableId.of(TABLE_ACL)).build();
831 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
832 + instructions.add(writeInstr);
833 + instructions.add(gotoInstr);
834 + OFMessage myIpEntry = factory.buildFlowAdd()
835 + .setTableId(TableId.of(TABLE_IPV4_UNICAST))
836 + .setMatch(match)
837 + .setInstructions(instructions)
838 + .setPriority(SLASH_24_PRIORITY)
839 + .setBufferId(OFBufferId.NO_BUFFER)
840 + .setIdleTimeout(0)
841 + .setHardTimeout(0)
842 + .setXid(getNextTransactionId())
843 + .build();
844 + msglist.add(myIpEntry);
845 + }
846 + write(msglist);
847 + log.debug("Adding {} subnet-ip-rules in sw {}", msglist.size(), getStringId());
848 + msglist.clear();
849 + }
850 +
851 + private void populateRoutes() throws IOException {
852 + List<OFMessage> msglist = new ArrayList<OFMessage>();
853 + // addresses where I know the next-hop's mac-address because it is a
854 + // router port - so I have an L3 interface to it (and an MPLS interface)
855 + List<RouteEntry> routerNextHopIps = getRouterNextHopIps();
856 + for (int i = 0; i < routerNextHopIps.size(); i++) {
857 + OFOxmEthType ethTypeIp = factory.oxms()
858 + .ethType(EthType.IPv4);
859 + OFOxmIpv4DstMasked ipPrefix = factory.oxms()
860 + .ipv4DstMasked(
861 + IPv4Address.of(routerNextHopIps.get(i).prefix),
862 + IPv4Address.of(routerNextHopIps.get(i).mask)
863 + );
864 + OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
865 + OFMatchV3 match = factory.buildMatchV3()
866 + .setOxmList(oxmListSlash32).build();
867 + OFAction outg = factory.actions().buildGroup()
868 + .setGroup(OFGroup.of(0xa0000000 | // mpls group id
869 + routerNextHopIps.get(i).nextHopPort))
870 + .build();
871 + // lots of actions before forwarding to mpls group, and
872 + // unfortunately
873 + // they need to be apply-actions
874 +
875 + OFAction pushlabel = factory.actions().pushMpls(EthType.MPLS_UNICAST);
876 + OFOxmMplsLabel l = factory.oxms()
877 + .mplsLabel(U32.of(routerNextHopIps.get(i).label));
878 + OFAction setlabelid = factory.actions().buildSetField()
879 + .setField(l).build();
880 + OFAction copyTtlOut = factory.actions().copyTtlOut();
881 + // OFAction setBos =
882 + // factory.actions().buildSetField().setField(bos).build();
883 +
884 + /*
885 + writeActions.add(pushlabel); // need to be apply actions so can be
886 + writeActions.add(copyTtlOut); // matched in pseudo-table
887 + //writeActions.add(setlabelid); // bad support in cpqd
888 + //writeActions.add(setBos); no support in loxigen
889 + */
890 +
891 + List<OFAction> applyActions = new ArrayList<OFAction>();
892 + applyActions.add(pushlabel);
893 + applyActions.add(copyTtlOut);
894 + OFInstruction applyInstr = factory.instructions().buildApplyActions()
895 + .setActions(applyActions).build();
896 + List<OFAction> writeActions = new ArrayList<OFAction>();
897 + writeActions.add(outg); // group will decr mpls-ttl, set mac-sa/da,
898 + // vlan
899 + OFInstruction writeInstr = factory.instructions().buildWriteActions()
900 + .setActions(writeActions).build();
901 +
902 + // necessary to match in pseudo-table to overcome cpqd 1.3 flaw
903 + OFInstruction writeMeta = factory.instructions().buildWriteMetadata()
904 + .setMetadata(U64.of(routerNextHopIps.get(i).label))
905 + .setMetadataMask(METADATA_MASK).build();
906 + /*OFInstruction gotoInstr = factory.instructions().buildGotoTable()
907 + .setTableId(TableId.of(TABLE_ACL)).build();*/
908 + OFInstruction gotoInstr = factory.instructions().buildGotoTable()
909 + .setTableId(TableId.of(TABLE_META)).build();
910 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
911 + instructions.add(applyInstr);
912 + // instructions.add(writeInstr);// cannot write here - causes switch
913 + // to crash
914 + instructions.add(writeMeta);
915 + instructions.add(gotoInstr);
916 +
917 + int priority = -1;
918 + if (routerNextHopIps.get(i).mask.equals("255.255.255.255")) {
919 + priority = MAX_PRIORITY;
920 + } else {
921 + priority = SLASH_24_PRIORITY;
922 + }
923 + OFMessage myIpEntry = factory.buildFlowAdd()
924 + .setTableId(TableId.of(TABLE_IPV4_UNICAST))
925 + .setMatch(match)
926 + .setInstructions(instructions)
927 + .setPriority(priority)
928 + .setBufferId(OFBufferId.NO_BUFFER)
929 + .setIdleTimeout(0)
930 + .setHardTimeout(0)
931 + .setXid(getNextTransactionId())
932 + .build();
933 + msglist.add(myIpEntry);
934 +
935 + // need to also handle psuedo-table entries to match-metadata and
936 + // set mpls
937 + // label-id
938 + OFOxmEthType ethTypeMpls = factory.oxms()
939 + .ethType(EthType.MPLS_UNICAST);
940 + OFOxmMetadataMasked meta = factory.oxms()
941 + .metadataMasked(
942 + OFMetadata.ofRaw(routerNextHopIps.get(i).label),
943 + OFMetadata.NO_MASK);
944 + OFOxmList oxmListMeta = OFOxmList.of(ethTypeMpls, meta);
945 + OFMatchV3 matchMeta = factory.buildMatchV3()
946 + .setOxmList(oxmListMeta).build();
947 + List<OFAction> writeActions2 = new ArrayList<OFAction>();
948 + writeActions2.add(setlabelid);
949 + OFAction outg2 = factory.actions().buildGroup()
950 + .setGroup(OFGroup.of(routerNextHopIps.get(i).nextHopPort |
951 + (192 << VLAN_ID_OFFSET)))
952 + .build();
953 + writeActions2.add(outg2);
954 + OFInstruction writeInstr2 = factory.instructions().buildWriteActions()
955 + .setActions(writeActions2).build();
956 + OFInstruction gotoInstr2 = factory.instructions().buildGotoTable()
957 + .setTableId(TableId.of(TABLE_ACL)).build();
958 + List<OFInstruction> instructions2 = new ArrayList<OFInstruction>();
959 + // unfortunately have to apply this action too
960 + OFInstruction applyInstr2 = factory.instructions().buildApplyActions()
961 + .setActions(writeActions2).build();
962 + instructions2.add(applyInstr2);
963 + // instructions2.add(writeInstr2);
964 + // instructions2.add(gotoInstr2);
965 +
966 + /*OFMatchV3 match3 = factory.buildMatchV3()
967 + .setOxmList(OFOxmList.of(meta)).build();
968 + OFInstruction clearInstruction = factory.instructions().clearActions();
969 + List<OFInstruction> instructions3 = new ArrayList<OFInstruction>();
970 + OFAction outc = factory.actions().buildOutput()
971 + .setPort(OFPort.CONTROLLER).setMaxLen(OFPCML_NO_BUFFER)
972 + .build();
973 + OFInstruction writec = factory.instructions()
974 + .writeActions(Collections.singletonList(outc));
975 + instructions3.add(clearInstruction);
976 + instructions3.add(writec);
977 + instructions3.add(gotoInstr2); */
978 + OFMessage myMetaEntry = factory.buildFlowAdd()
979 + .setTableId(TableId.of(TABLE_META))
980 + .setMatch(matchMeta)
981 + .setInstructions(instructions2)
982 + .setPriority(MAX_PRIORITY)
983 + .setBufferId(OFBufferId.NO_BUFFER)
984 + .setIdleTimeout(0)
985 + .setHardTimeout(0)
986 + .setXid(getNextTransactionId())
987 + .build();
988 + msglist.add(myMetaEntry);
989 +
990 + }
991 + write(msglist);
992 + log.debug("Adding {} next-hop-router-rules in sw {}", msglist.size(),
993 + getStringId());
994 +
995 + // add a table-miss entry to table 4 for debugging - leave it out
996 + // unclear packet state - causes switch to crash
997 + // populateTableMissEntry(TABLE_META, false, true,
998 + // true, TABLE_ACL);
999 + }
1000 +
1001 + private void populateHostRoutes() throws IOException {
1002 + List<OFMessage> msglist = new ArrayList<OFMessage>();
1003 + // addresses where I know the next hop's mac-address and I can set the
1004 + // destination mac in the match-instruction.write-action
1005 + // either I sent out arp-request or I got an arp-request from this host
1006 + List<RouteEntry> hostNextHopIps = getHostNextHopIps();
1007 + for (int i = 0; i < hostNextHopIps.size(); i++) {
1008 + OFOxmEthType ethTypeIp = factory.oxms()
1009 + .ethType(EthType.IPv4);
1010 + OFOxmIpv4DstMasked ipPrefix = factory.oxms()
1011 + .ipv4DstMasked(
1012 + IPv4Address.of(hostNextHopIps.get(i).prefix),
1013 + IPv4Address.NO_MASK); // host addr should be /32
1014 + OFOxmList oxmListSlash32 = OFOxmList.of(ethTypeIp, ipPrefix);
1015 + OFMatchV3 match = factory.buildMatchV3()
1016 + .setOxmList(oxmListSlash32).build();
1017 + OFAction setDmac = null, outg = null;
1018 + OFOxmEthDst dmac = factory.oxms()
1019 + .ethDst(MacAddress.of(hostNextHopIps.get(i).dstMac));
1020 + setDmac = factory.actions().buildSetField()
1021 + .setField(dmac).build();
1022 + outg = factory.actions().buildGroup()
1023 + .setGroup(OFGroup.of(0x20000000 | hostNextHopIps.get(i).nextHopPort)) // l3group
1024 + // id
1025 + .build();
1026 + List<OFAction> writeActions = new ArrayList<OFAction>();
1027 + writeActions.add(setDmac);
1028 + writeActions.add(outg);
1029 + OFInstruction writeInstr = factory.instructions().buildWriteActions()
1030 + .setActions(writeActions).build();
1031 + OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1032 + .setTableId(TableId.of(TABLE_ACL)).build();
1033 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1034 + instructions.add(writeInstr);
1035 + instructions.add(gotoInstr);
1036 + OFMessage myIpEntry = factory.buildFlowAdd()
1037 + .setTableId(TableId.of(TABLE_IPV4_UNICAST))
1038 + .setMatch(match)
1039 + .setInstructions(instructions)
1040 + .setPriority(MAX_PRIORITY) // highest priority for exact
1041 + // match
1042 + .setBufferId(OFBufferId.NO_BUFFER)
1043 + .setIdleTimeout(0)
1044 + .setHardTimeout(0)
1045 + .setXid(getNextTransactionId())
1046 + .build();
1047 + msglist.add(myIpEntry);
1048 + }
1049 + write(msglist);
1050 + log.debug("Adding {} next-hop-host-rules in sw {}", msglist.size(), getStringId());
1051 + }
1052 +
1053 + private static class MplsEntry {
1054 + int labelid;
1055 + int portnum;
1056 +
1057 + public MplsEntry(int labelid, int portnum) {
1058 + this.labelid = labelid;
1059 + this.portnum = portnum;
1060 + }
1061 + }
1062 +
1063 + private List<MplsEntry> getMplsEntries() {
1064 + List<MplsEntry> myLabels = new ArrayList<MplsEntry>();
1065 + if (getId() == 0x1) {
1066 + myLabels.add(new MplsEntry(101, OFPort.CONTROLLER.getPortNumber()));
1067 + myLabels.add(new MplsEntry(103, 6));
1068 + }
1069 + if (getId() == 0x2) {
1070 + myLabels.add(new MplsEntry(103, 2));
1071 + myLabels.add(new MplsEntry(102, OFPort.CONTROLLER.getPortNumber()));
1072 + myLabels.add(new MplsEntry(101, 1));
1073 + }
1074 + if (getId() == 0x3) {
1075 + myLabels.add(new MplsEntry(103, OFPort.CONTROLLER.getPortNumber()));
1076 + myLabels.add(new MplsEntry(101, 2));
1077 + }
1078 + return myLabels;
1079 + }
1080 +
1081 + private void populateMplsTable() throws IOException {
1082 + List<OFMessage> msglist = new ArrayList<OFMessage>();
1083 + List<MplsEntry> lfibEntries = getMplsEntries();
1084 + for (int i = 0; i < lfibEntries.size(); i++) {
1085 + OFOxmEthType ethTypeMpls = factory.oxms()
1086 + .ethType(EthType.MPLS_UNICAST);
1087 + OFOxmMplsLabel labelid = factory.oxms()
1088 + .mplsLabel(U32.of(lfibEntries.get(i).labelid));
1089 + OFOxmList oxmList = OFOxmList.of(ethTypeMpls, labelid);
1090 + OFMatchV3 matchlabel = factory.buildMatchV3()
1091 + .setOxmList(oxmList).build();
1092 + OFAction poplabel = factory.actions().popMpls(EthType.IPv4);
1093 + OFAction sendTo = null;
1094 + if (lfibEntries.get(i).portnum == OFPort.CONTROLLER.getPortNumber()) {
1095 + sendTo = factory.actions().output(OFPort.CONTROLLER,
1096 + OFPCML_NO_BUFFER);
1097 + } else {
1098 + sendTo = factory.actions().group(OFGroup.of(
1099 + 0xa0000000 | lfibEntries.get(i).portnum));
1100 + }
1101 + List<OFAction> writeActions = new ArrayList<OFAction>();
1102 + writeActions.add(poplabel);
1103 + writeActions.add(sendTo);
1104 + OFInstruction writeInstr = factory.instructions().buildWriteActions()
1105 + .setActions(writeActions).build();
1106 + OFInstruction gotoInstr = factory.instructions().buildGotoTable()
1107 + .setTableId(TableId.of(TABLE_ACL)).build();
1108 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1109 + instructions.add(writeInstr);
1110 + instructions.add(gotoInstr);
1111 + OFMessage myMplsEntry = factory.buildFlowAdd()
1112 + .setTableId(TableId.of(TABLE_MPLS))
1113 + .setMatch(matchlabel)
1114 + .setInstructions(instructions)
1115 + .setPriority(MAX_PRIORITY) // exact match and exclusive
1116 + .setBufferId(OFBufferId.NO_BUFFER)
1117 + .setIdleTimeout(0)
1118 + .setHardTimeout(0)
1119 + .setXid(getNextTransactionId())
1120 + .build();
1121 + msglist.add(myMplsEntry);
1122 + }
1123 + write(msglist);
1124 + log.debug("Adding {} mpls-forwarding-rules in sw {}", msglist.size(),
1125 + getStringId());
1126 +
1127 + // match for everything else to send to ACL table. Essentially
1128 + // the table miss flow entry
1129 + populateTableMissEntry(TABLE_MPLS, false, true,
1130 + true, TABLE_ACL);
1131 +
1132 + }
1133 +
1134 + /**
1135 + * By default if none of the booleans in the call are set, then the
1136 + * table-miss entry is added with no instructions, which means that pipeline
1137 + * execution will stop, and the action set associated with the packet will
1138 + * be executed.
1139 + *
1140 + * @param tableToAdd
1141 + * @param toControllerNow as an APPLY_ACTION instruction
1142 + * @param toControllerWrite as a WRITE_ACITION instruction
1143 + * @param toTable as a GOTO_TABLE instruction
1144 + * @param tableToSend
1145 + * @throws IOException
1146 + */
1147 + @SuppressWarnings("unchecked")
1148 + private void populateTableMissEntry(int tableToAdd, boolean toControllerNow,
1149 + boolean toControllerWrite,
1150 + boolean toTable, int tableToSend) {
1151 + OFOxmList oxmList = OFOxmList.EMPTY;
1152 + OFMatchV3 match = factory.buildMatchV3()
1153 + .setOxmList(oxmList)
1154 + .build();
1155 + OFAction outc = factory.actions()
1156 + .buildOutput()
1157 + .setPort(OFPort.CONTROLLER)
1158 + .setMaxLen(OFPCML_NO_BUFFER)
1159 + .build();
1160 + List<OFInstruction> instructions = new ArrayList<OFInstruction>();
1161 + if (toControllerNow) {
1162 + // table-miss instruction to send to controller immediately
1163 + OFInstruction instr = factory.instructions()
1164 + .buildApplyActions()
1165 + .setActions(Collections.singletonList(outc))
1166 + .build();
1167 + instructions.add(instr);
1168 + }
1169 +
1170 + if (toControllerWrite) {
1171 + // table-miss instruction to write-action to send to controller
1172 + // this will be executed whenever the action-set gets executed
1173 + OFInstruction instr = factory.instructions()
1174 + .buildWriteActions()
1175 + .setActions(Collections.singletonList(outc))
1176 + .build();
1177 + instructions.add(instr);
1178 + }
1179 +
1180 + if (toTable) {
1181 + // table-miss instruction to goto-table x
1182 + OFInstruction instr = factory.instructions()
1183 + .gotoTable(TableId.of(tableToSend));
1184 + instructions.add(instr);
1185 + }
1186 +
1187 + if (!toControllerNow && !toControllerWrite && !toTable) {
1188 + // table-miss has no instruction - at which point action-set will be
1189 + // executed - if there is an action to output/group in the action
1190 + // set
1191 + // the packet will be sent there, otherwise it will be dropped.
1192 + instructions = (List<OFInstruction>) Collections.EMPTY_LIST;
1193 + }
1194 +
1195 + OFMessage tableMissEntry = factory.buildFlowAdd()
1196 + .setTableId(TableId.of(tableToAdd))
1197 + .setMatch(match) // match everything
1198 + .setInstructions(instructions)
1199 + .setPriority(MIN_PRIORITY)
1200 + .setBufferId(OFBufferId.NO_BUFFER)
1201 + .setIdleTimeout(0)
1202 + .setHardTimeout(0)
1203 + .setXid(getNextTransactionId())
1204 + .build();
1205 + sendMsg(tableMissEntry);
1206 + }
1207 +
1208 + private void sendBarrier(boolean finalBarrier) {
1209 + int xid = getNextTransactionId();
1210 + if (finalBarrier) {
1211 + barrierXidToWaitFor = xid;
1212 + }
1213 + OFBarrierRequest br = factory
1214 + .buildBarrierRequest()
1215 + .setXid(xid)
1216 + .build();
1217 + sendMsg(br);
1218 + }
1219 +
1220 + @Override
1221 + public void sendMsg(OFMessage m) {
1222 + channel.write(m);
1223 + }
1224 +
1225 + @Override
1226 + public void write(List<OFMessage> msgs) {
1227 + for (OFMessage m : msgs) {
1228 + channel.write(m);
1229 + }
1230 + }
1231 +
1232 + @Override
1233 + public Boolean supportNxRole() {
1234 + return false;
1235 + }
1236 +
1237 +}
1 +package org.onlab.onos.of.drivers;
2 +
3 +import org.onlab.onos.of.controller.Dpid;
4 +import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
5 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
6 +import org.projectfloodlight.openflow.protocol.OFMessage;
7 +
8 +/**
9 + * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
10 + * (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
11 + * 1.11.90 (or whatever version + build) Serial : None
12 + */
13 +public class OFSwitchImplOVS10 extends AbstractOpenFlowSwitch {
14 +
15 + public OFSwitchImplOVS10(Dpid dpid, OFDescStatsReply desc) {
16 + super(dpid);
17 + setSwitchDescription(desc);
18 +
19 + }
20 +
21 + /* (non-Javadoc)
22 + * @see java.lang.Object#toString()
23 + */
24 + @Override
25 + public String toString() {
26 + return "OFSwitchImplOVS10 [" + ((channel != null)
27 + ? channel.getRemoteAddress() : "?")
28 + + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
29 + }
30 +
31 + @Override
32 + public void sendMsg(OFMessage m) {
33 + channel.write(m);
34 + }
35 +
36 + @Override
37 + public Boolean supportNxRole() {
38 + return true;
39 + }
40 +
41 + @Override
42 + public void startDriverHandshake() {}
43 +
44 + @Override
45 + public boolean isDriverHandshakeComplete() {
46 + return true;
47 + }
48 +
49 + @Override
50 + public void processDriverHandshakeMessage(OFMessage m) {}
51 +}
1 +package org.onlab.onos.of.drivers;
2 +
3 +import java.util.concurrent.atomic.AtomicBoolean;
4 +
5 +import org.onlab.onos.of.controller.Dpid;
6 +import org.onlab.onos.of.controller.impl.internal.AbstractOpenFlowSwitch;
7 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeAlreadyStarted;
8 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeCompleted;
9 +import org.onlab.onos.of.controller.impl.internal.SwitchDriverSubHandshakeNotStarted;
10 +import org.projectfloodlight.openflow.protocol.OFBarrierRequest;
11 +import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
12 +import org.projectfloodlight.openflow.protocol.OFErrorMsg;
13 +import org.projectfloodlight.openflow.protocol.OFFactory;
14 +import org.projectfloodlight.openflow.protocol.OFMessage;
15 +import org.slf4j.Logger;
16 +import org.slf4j.LoggerFactory;
17 +
18 +/**
19 + * OFDescriptionStatistics Vendor (Manufacturer Desc.): Nicira, Inc. Make
20 + * (Hardware Desc.) : Open vSwitch Model (Datapath Desc.) : None Software :
21 + * 2.1.0 (or whatever version + build) Serial : None
22 + */
23 +public class OFSwitchImplOVS13 extends AbstractOpenFlowSwitch {
24 +
25 + private static Logger log =
26 + LoggerFactory.getLogger(OFSwitchImplOVS13.class);
27 +
28 + private AtomicBoolean driverHandshakeComplete;
29 + private OFFactory factory;
30 + private long barrierXidToWaitFor = -1;
31 +
32 + public OFSwitchImplOVS13(Dpid dpid, OFDescStatsReply desc) {
33 + super(dpid);
34 + driverHandshakeComplete = new AtomicBoolean(false);
35 + setSwitchDescription(desc);
36 + }
37 +
38 + @Override
39 + public String toString() {
40 + return "OFSwitchImplOVS13 [" + ((channel != null)
41 + ? channel.getRemoteAddress() : "?")
42 + + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
43 + }
44 +
45 + @Override
46 + public void startDriverHandshake() {
47 + log.debug("Starting driver handshake for sw {}", getStringId());
48 + if (startDriverHandshakeCalled) {
49 + throw new SwitchDriverSubHandshakeAlreadyStarted();
50 + }
51 + startDriverHandshakeCalled = true;
52 + factory = factory();
53 + configureSwitch();
54 + }
55 +
56 + @Override
57 + public boolean isDriverHandshakeComplete() {
58 + if (!startDriverHandshakeCalled) {
59 + throw new SwitchDriverSubHandshakeNotStarted();
60 + }
61 + return driverHandshakeComplete.get();
62 + }
63 +
64 + @Override
65 + public void processDriverHandshakeMessage(OFMessage m) {
66 + if (!startDriverHandshakeCalled) {
67 + throw new SwitchDriverSubHandshakeNotStarted();
68 + }
69 + if (driverHandshakeComplete.get()) {
70 + throw new SwitchDriverSubHandshakeCompleted(m);
71 + }
72 +
73 + switch (m.getType()) {
74 + case BARRIER_REPLY:
75 + if (m.getXid() == barrierXidToWaitFor) {
76 + driverHandshakeComplete.set(true);
77 + }
78 + break;
79 +
80 + case ERROR:
81 + log.error("Switch {} Error {}", getStringId(), (OFErrorMsg) m);
82 + break;
83 +
84 + case FEATURES_REPLY:
85 + break;
86 + case FLOW_REMOVED:
87 + break;
88 + case GET_ASYNC_REPLY:
89 + // OFAsyncGetReply asrep = (OFAsyncGetReply)m;
90 + // decodeAsyncGetReply(asrep);
91 + break;
92 +
93 + case PACKET_IN:
94 + break;
95 + case PORT_STATUS:
96 + break;
97 + case QUEUE_GET_CONFIG_REPLY:
98 + break;
99 + case ROLE_REPLY:
100 + break;
101 +
102 + case STATS_REPLY:
103 + // processStatsReply((OFStatsReply) m);
104 + break;
105 +
106 + default:
107 + log.debug("Received message {} during switch-driver subhandshake "
108 + + "from switch {} ... Ignoring message", m, getStringId());
109 +
110 + }
111 + }
112 +
113 +
114 + private void configureSwitch() {
115 + sendBarrier(true);
116 + }
117 +
118 +
119 + private void sendBarrier(boolean finalBarrier) {
120 + int xid = getNextTransactionId();
121 + if (finalBarrier) {
122 + barrierXidToWaitFor = xid;
123 + }
124 + OFBarrierRequest br = factory
125 + .buildBarrierRequest()
126 + .setXid(xid)
127 + .build();
128 + sendMsg(br);
129 + }
130 +
131 + @Override
132 + public void sendMsg(OFMessage m) {
133 + channel.write(m);
134 + }
135 +
136 + @Override
137 + public Boolean supportNxRole() {
138 + return false;
139 + }
140 +}