Showing
10 changed files
with
1647 additions
and
80 deletions
... | @@ -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 | +} |
-
Please register or login to post a comment