Committed by
Jonathan Hart
Added SpringOpenTTP switch driver (ONOS-822/ONOS-682).
Modified OpenFlpwRuleProvider to support FlowRule with multiple-table feature. Change-Id: If95284077b96213593c5c1e3ab12900001bf49a2
Showing
2 changed files
with
553 additions
and
11 deletions
... | @@ -16,28 +16,99 @@ | ... | @@ -16,28 +16,99 @@ |
16 | package org.onosproject.openflow.drivers; | 16 | package org.onosproject.openflow.drivers; |
17 | 17 | ||
18 | import org.onosproject.openflow.controller.Dpid; | 18 | import org.onosproject.openflow.controller.Dpid; |
19 | +import org.onosproject.openflow.controller.RoleState; | ||
19 | import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch; | 20 | import org.onosproject.openflow.controller.driver.AbstractOpenFlowSwitch; |
21 | +import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeAlreadyStarted; | ||
22 | +import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeCompleted; | ||
23 | +import org.onosproject.openflow.controller.driver.SwitchDriverSubHandshakeNotStarted; | ||
24 | +import org.projectfloodlight.openflow.protocol.OFAsyncGetReply; | ||
25 | +import org.projectfloodlight.openflow.protocol.OFBarrierRequest; | ||
26 | +import org.projectfloodlight.openflow.protocol.OFErrorMsg; | ||
27 | +import org.projectfloodlight.openflow.protocol.OFGroupDescStatsReply; | ||
28 | +import org.projectfloodlight.openflow.protocol.OFGroupFeaturesStatsReply; | ||
29 | +import org.projectfloodlight.openflow.protocol.OFMatchV3; | ||
30 | +import org.projectfloodlight.openflow.protocol.OFOxmList; | ||
31 | +import org.projectfloodlight.openflow.protocol.OFPortDesc; | ||
32 | +import org.projectfloodlight.openflow.protocol.OFStatsReply; | ||
33 | +import org.projectfloodlight.openflow.protocol.OFFlowMod; | ||
34 | +import org.projectfloodlight.openflow.protocol.OFDescStatsReply; | ||
35 | +import org.projectfloodlight.openflow.protocol.OFFactory; | ||
20 | import org.projectfloodlight.openflow.protocol.OFMessage; | 36 | import org.projectfloodlight.openflow.protocol.OFMessage; |
37 | +import org.projectfloodlight.openflow.protocol.OFType; | ||
38 | +import org.projectfloodlight.openflow.protocol.action.OFAction; | ||
39 | +import org.projectfloodlight.openflow.protocol.instruction.OFInstruction; | ||
40 | +import org.projectfloodlight.openflow.protocol.oxm.OFOxmEthType; | ||
41 | +import org.projectfloodlight.openflow.protocol.oxm.OFOxmInPort; | ||
42 | +import org.projectfloodlight.openflow.protocol.oxm.OFOxmVlanVid; | ||
43 | +import org.projectfloodlight.openflow.types.EthType; | ||
44 | +import org.projectfloodlight.openflow.types.MacAddress; | ||
45 | +import org.projectfloodlight.openflow.types.OFBufferId; | ||
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.util.HexString; | ||
21 | 51 | ||
52 | +import java.io.IOException; | ||
53 | +import java.util.ArrayList; | ||
54 | +import java.util.Collections; | ||
22 | import java.util.List; | 55 | import java.util.List; |
56 | +import java.util.concurrent.atomic.AtomicBoolean; | ||
23 | 57 | ||
24 | -/** | ||
25 | - * Created by sanghoshin on 1/22/15. | ||
26 | - */ | ||
27 | public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { | 58 | public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { |
28 | 59 | ||
29 | - protected OFSwitchImplSpringOpenTTP(Dpid dp) { | 60 | + private OFFactory factory; |
30 | - super(dp); | ||
31 | - } | ||
32 | 61 | ||
33 | - @Override | 62 | + private final AtomicBoolean driverHandshakeComplete; |
34 | - public void write(OFMessage msg) { | 63 | + private AtomicBoolean haltStateMachine; |
64 | + | ||
65 | + private DriverState driverState; | ||
66 | + | ||
67 | + /* Default table ID - compatible with CpqD switch */ | ||
68 | + private static final int TABLE_VLAN = 0; | ||
69 | + private static final int TABLE_TMAC = 1; | ||
70 | + private static final int TABLE_IPV4_UNICAST = 2; | ||
71 | + private static final int TABLE_MPLS = 3; | ||
72 | + private static final int TABLE_ACL = 5; | ||
73 | + | ||
74 | + private static final long TEST_FLOW_REMOVED_MASK = 0xf; | ||
75 | + private static final long TEST_PACKET_IN_MASK = 0x7; | ||
76 | + private static final long TEST_PORT_STATUS_MASK = 0x7; | ||
35 | 77 | ||
78 | + private static final int OFPCML_NO_BUFFER = 0xffff; | ||
79 | + | ||
80 | + private long barrierXidToWaitFor = -1; | ||
81 | + | ||
82 | + /* Set the default values. These variables will get | ||
83 | + * overwritten based on the switch vendor type | ||
84 | + */ | ||
85 | + protected int vlanTableId = TABLE_VLAN; | ||
86 | + protected int tmacTableId = TABLE_TMAC; | ||
87 | + protected int ipv4UnicastTableId = TABLE_IPV4_UNICAST; | ||
88 | + protected int mplsTableId = TABLE_MPLS; | ||
89 | + protected int aclTableId = TABLE_ACL; | ||
90 | + | ||
91 | + /* priority values for OF message */ | ||
92 | + private static final short MAX_PRIORITY = (short) 0xffff; | ||
93 | + private static final short PRIORITY_MULTIPLIER = (short) 2046; | ||
94 | + private static final short MIN_PRIORITY = 0x0; | ||
95 | + | ||
96 | + | ||
97 | + protected OFSwitchImplSpringOpenTTP(Dpid dpid, OFDescStatsReply desc) { | ||
98 | + super(dpid); | ||
99 | + driverHandshakeComplete = new AtomicBoolean(false); | ||
100 | + haltStateMachine = new AtomicBoolean(false); | ||
101 | + driverState = DriverState.INIT; | ||
102 | + setSwitchDescription(desc); | ||
36 | } | 103 | } |
37 | 104 | ||
38 | - @Override | ||
39 | - public void write(List<OFMessage> msgs) { | ||
40 | 105 | ||
106 | + @Override | ||
107 | + public String toString() { | ||
108 | + return "OFSwitchImplSpringOpenTTP [" + ((channel != null) | ||
109 | + ? channel.getRemoteAddress() : "?") | ||
110 | + + " DPID[" + ((this.getStringId() != null) ? | ||
111 | + this.getStringId() : "?") + "]]"; | ||
41 | } | 112 | } |
42 | 113 | ||
43 | @Override | 114 | @Override |
... | @@ -47,17 +118,458 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { | ... | @@ -47,17 +118,458 @@ public class OFSwitchImplSpringOpenTTP extends AbstractOpenFlowSwitch { |
47 | 118 | ||
48 | @Override | 119 | @Override |
49 | public void startDriverHandshake() { | 120 | public void startDriverHandshake() { |
121 | + log.debug("Starting driver handshake for sw {}", getStringId()); | ||
122 | + if (startDriverHandshakeCalled) { | ||
123 | + throw new SwitchDriverSubHandshakeAlreadyStarted(); | ||
124 | + } | ||
125 | + startDriverHandshakeCalled = true; | ||
126 | + factory = this.factory(); | ||
50 | 127 | ||
128 | + try { | ||
129 | + nextDriverState(); | ||
130 | + } catch (IOException e) { | ||
131 | + log.error("Error {} during driver handshake for sw {}", e.getCause(), | ||
132 | + getStringId()); | ||
133 | + } | ||
51 | } | 134 | } |
52 | 135 | ||
53 | @Override | 136 | @Override |
54 | public boolean isDriverHandshakeComplete() { | 137 | public boolean isDriverHandshakeComplete() { |
55 | - return false; | 138 | + if (!startDriverHandshakeCalled) { |
139 | + throw new SwitchDriverSubHandshakeNotStarted(); | ||
140 | + } | ||
141 | + return driverHandshakeComplete.get(); | ||
56 | } | 142 | } |
57 | 143 | ||
58 | @Override | 144 | @Override |
59 | public void processDriverHandshakeMessage(OFMessage m) { | 145 | public void processDriverHandshakeMessage(OFMessage m) { |
146 | + if (!startDriverHandshakeCalled) { | ||
147 | + throw new SwitchDriverSubHandshakeNotStarted(); | ||
148 | + } | ||
149 | + if (driverHandshakeComplete.get()) { | ||
150 | + throw new SwitchDriverSubHandshakeCompleted(m); | ||
151 | + } | ||
152 | + try { | ||
153 | + processOFMessage(m); | ||
154 | + } catch (IOException e) { | ||
155 | + log.error("Error generated when processing OFMessage {}", e.getCause()); | ||
156 | + } | ||
157 | + } | ||
158 | + | ||
159 | + @Override | ||
160 | + public void write(OFMessage msg) { | ||
161 | + this.channel.write(Collections.singletonList(msg)); | ||
162 | + } | ||
163 | + | ||
164 | + @Override | ||
165 | + public void write(List<OFMessage> msgs) { | ||
166 | + this.channel.write(msgs); | ||
167 | + } | ||
168 | + | ||
169 | + @Override | ||
170 | + public void sendMsg(OFMessage m, TableType tableType) { | ||
171 | + | ||
172 | + if (m.getType() == OFType.FLOW_MOD) { | ||
173 | + OFFlowMod flowMod = (OFFlowMod) m; | ||
174 | + OFFlowMod.Builder builder = flowMod.createBuilder(); | ||
175 | + builder.setTableId(getTableId(tableType)); | ||
176 | + OFFlowMod newFlowMod = builder.build(); | ||
177 | + if (role == RoleState.MASTER) { | ||
178 | + this.write(newFlowMod); | ||
179 | + } | ||
180 | + } else { | ||
181 | + if (role == RoleState.MASTER) { | ||
182 | + this.write(m); | ||
183 | + } | ||
184 | + } | ||
185 | + } | ||
186 | + | ||
187 | + /* | ||
188 | + * Driver handshake state machine | ||
189 | + */ | ||
190 | + | ||
191 | + enum DriverState { | ||
192 | + INIT, | ||
193 | + SET_TABLE_MISS_ENTRIES, | ||
194 | + SET_TABLE_VLAN_TMAC, | ||
195 | + AUDIT_GROUPS, | ||
196 | + SET_GROUPS, | ||
197 | + VERIFY_GROUPS, | ||
198 | + SET_ADJACENCY_LABELS, | ||
199 | + EXIT | ||
200 | + } | ||
60 | 201 | ||
202 | + protected void nextDriverState() throws IOException { | ||
203 | + DriverState currentState = driverState; | ||
204 | + if (haltStateMachine.get()) { | ||
205 | + return; | ||
61 | } | 206 | } |
207 | + switch (currentState) { | ||
208 | + case INIT: | ||
209 | + driverState = DriverState.SET_TABLE_MISS_ENTRIES; | ||
210 | + setTableMissEntries(); | ||
211 | + sendHandshakeBarrier(); | ||
212 | + break; | ||
213 | + case SET_TABLE_MISS_ENTRIES: | ||
214 | + driverState = DriverState.SET_TABLE_VLAN_TMAC; | ||
215 | + /* TODO: read network configuration | ||
216 | + boolean isConfigured = getNetworkConfig(); | ||
217 | + if (!isConfigured) { | ||
218 | + return; // this will result in a handshake timeout | ||
219 | + } | ||
220 | + */ | ||
221 | + populateTableVlan(); | ||
222 | + populateTableTMac(); | ||
223 | + sendHandshakeBarrier(); | ||
224 | + break; | ||
225 | + case SET_TABLE_VLAN_TMAC: | ||
226 | + driverState = DriverState.EXIT; | ||
227 | + driverHandshakeComplete.set(true); | ||
228 | + log.debug("Driver handshake is complete"); | ||
229 | + break; | ||
230 | + case EXIT: | ||
231 | + default: | ||
232 | + driverState = DriverState.EXIT; | ||
233 | + log.error("Driver handshake has exited for sw: {}", getStringId()); | ||
234 | + } | ||
235 | + } | ||
236 | + | ||
237 | + private void processStatsReply(OFStatsReply sr) { | ||
238 | + switch (sr.getStatsType()) { | ||
239 | + case AGGREGATE: | ||
240 | + break; | ||
241 | + case DESC: | ||
242 | + break; | ||
243 | + case EXPERIMENTER: | ||
244 | + break; | ||
245 | + case FLOW: | ||
246 | + break; | ||
247 | + case GROUP_DESC: | ||
248 | + processGroupDesc((OFGroupDescStatsReply) sr); | ||
249 | + break; | ||
250 | + case GROUP_FEATURES: | ||
251 | + processGroupFeatures((OFGroupFeaturesStatsReply) sr); | ||
252 | + break; | ||
253 | + case METER_CONFIG: | ||
254 | + break; | ||
255 | + case METER_FEATURES: | ||
256 | + break; | ||
257 | + case PORT_DESC: | ||
258 | + break; | ||
259 | + case TABLE_FEATURES: | ||
260 | + break; | ||
261 | + default: | ||
262 | + break; | ||
263 | + | ||
264 | + } | ||
265 | + } | ||
266 | + | ||
267 | + private void processOFMessage(OFMessage m) throws IOException { | ||
268 | + switch (m.getType()) { | ||
269 | + case BARRIER_REPLY: | ||
270 | + processBarrierReply(m); | ||
271 | + break; | ||
272 | + | ||
273 | + case ERROR: | ||
274 | + processErrorMessage(m); | ||
275 | + break; | ||
276 | + | ||
277 | + case GET_ASYNC_REPLY: | ||
278 | + OFAsyncGetReply asrep = (OFAsyncGetReply) m; | ||
279 | + decodeAsyncGetReply(asrep); | ||
280 | + break; | ||
281 | + | ||
282 | + case PACKET_IN: | ||
283 | + // not ready to handle packet-ins | ||
284 | + break; | ||
285 | + | ||
286 | + case QUEUE_GET_CONFIG_REPLY: | ||
287 | + // not doing queue config yet | ||
288 | + break; | ||
289 | + | ||
290 | + case STATS_REPLY: | ||
291 | + processStatsReply((OFStatsReply) m); | ||
292 | + break; | ||
62 | 293 | ||
294 | + case ROLE_REPLY: // channelHandler should handle this | ||
295 | + case PORT_STATUS: // channelHandler should handle this | ||
296 | + case FEATURES_REPLY: // don't care | ||
297 | + case FLOW_REMOVED: // don't care | ||
298 | + default: | ||
299 | + log.debug("Received message {} during switch-driver subhandshake " | ||
300 | + + "from switch {} ... Ignoring message", m, getStringId()); | ||
301 | + } | ||
302 | + } | ||
303 | + | ||
304 | + private void processBarrierReply(OFMessage m) throws IOException { | ||
305 | + if (m.getXid() == barrierXidToWaitFor) { | ||
306 | + // Driver state-machine progresses to the next state. | ||
307 | + // If Barrier messages is not received, then eventually | ||
308 | + // the ChannelHandler state machine will timeout, and the switch | ||
309 | + // will be disconnected. | ||
310 | + nextDriverState(); | ||
311 | + } else { | ||
312 | + log.error("Received incorrect barrier-message xid {} (expected: {}) in " | ||
313 | + + "switch-driver state {} for switch {}", m, barrierXidToWaitFor, | ||
314 | + driverState, getStringId()); | ||
315 | + } | ||
316 | + } | ||
317 | + | ||
318 | + private void processErrorMessage(OFMessage m) { | ||
319 | + log.error("Switch {} Error {} in DriverState", getStringId(), | ||
320 | + (OFErrorMsg) m, driverState); | ||
321 | + } | ||
322 | + | ||
323 | + private void processGroupFeatures(OFGroupFeaturesStatsReply gfsr) { | ||
324 | + log.info("Sw: {} Group Features {}", getStringId(), gfsr); | ||
325 | + } | ||
326 | + | ||
327 | + private void processGroupDesc(OFGroupDescStatsReply gdsr) { | ||
328 | + log.info("Sw: {} Group Desc {}", getStringId(), gdsr); | ||
329 | + } | ||
330 | + | ||
331 | + /* | ||
332 | + * Utility functions | ||
333 | + */ | ||
334 | + | ||
335 | + private void decodeAsyncGetReply(OFAsyncGetReply rep) { | ||
336 | + long frm = rep.getFlowRemovedMaskEqualMaster(); | ||
337 | + //long frs = rep.getFlowRemovedMaskSlave(); | ||
338 | + long pim = rep.getPacketInMaskEqualMaster(); | ||
339 | + //long pis = rep.getPacketInMaskSlave(); | ||
340 | + long psm = rep.getPortStatusMaskEqualMaster(); | ||
341 | + //long pss = rep.getPortStatusMaskSlave(); | ||
342 | + | ||
343 | + if (role == RoleState.MASTER || role == RoleState.EQUAL) { // should separate | ||
344 | + log.info("FRM:{}", HexString.toHexString((frm & TEST_FLOW_REMOVED_MASK))); | ||
345 | + log.info("PIM:{}", HexString.toHexString((pim & TEST_PACKET_IN_MASK))); | ||
346 | + log.info("PSM:{}", HexString.toHexString((psm & TEST_PORT_STATUS_MASK))); | ||
347 | + } | ||
348 | + } | ||
349 | + | ||
350 | + protected void setTableMissEntries() throws IOException { | ||
351 | + // set all table-miss-entries | ||
352 | + populateTableMissEntry(vlanTableId, true, false, false, -1); | ||
353 | + populateTableMissEntry(tmacTableId, true, false, false, -1); | ||
354 | + populateTableMissEntry(ipv4UnicastTableId, false, true, true, | ||
355 | + aclTableId); | ||
356 | + populateTableMissEntry(mplsTableId, false, true, true, | ||
357 | + aclTableId); | ||
358 | + populateTableMissEntry(aclTableId, false, false, false, -1); | ||
359 | + log.debug("TableMissEntries are set"); | ||
360 | + } | ||
361 | + | ||
362 | + /** | ||
363 | + * Adds a table-miss-entry to a pipeline table. | ||
364 | + * <p> | ||
365 | + * The table-miss-entry can be added with 'write-actions' or | ||
366 | + * 'apply-actions'. It can also add a 'goto-table' instruction. By default | ||
367 | + * if none of the booleans in the call are set, then the table-miss entry is | ||
368 | + * added with no instructions, which means that if a packet hits the | ||
369 | + * table-miss-entry, pipeline execution will stop, and the action set | ||
370 | + * associated with the packet will be executed. | ||
371 | + * | ||
372 | + * @param tableToAdd the table to where the table-miss-entry will be added | ||
373 | + * @param toControllerNow as an APPLY_ACTION instruction | ||
374 | + * @param toControllerWrite as a WRITE_ACTION instruction | ||
375 | + * @param toTable as a GOTO_TABLE instruction | ||
376 | + * @param tableToSend the table to send as per the GOTO_TABLE instruction it | ||
377 | + * needs to be set if 'toTable' is true. Ignored of 'toTable' is | ||
378 | + * false. | ||
379 | + * @throws IOException | ||
380 | + */ | ||
381 | + protected void populateTableMissEntry(int tableToAdd, boolean toControllerNow, | ||
382 | + boolean toControllerWrite, | ||
383 | + boolean toTable, int tableToSend) throws IOException { | ||
384 | + OFOxmList oxmList = OFOxmList.EMPTY; | ||
385 | + OFMatchV3 match = factory.buildMatchV3() | ||
386 | + .setOxmList(oxmList) | ||
387 | + .build(); | ||
388 | + OFAction outc = factory.actions() | ||
389 | + .buildOutput() | ||
390 | + .setPort(OFPort.CONTROLLER) | ||
391 | + .setMaxLen(OFPCML_NO_BUFFER) | ||
392 | + .build(); | ||
393 | + List<OFInstruction> instructions = new ArrayList<OFInstruction>(); | ||
394 | + if (toControllerNow) { | ||
395 | + // table-miss instruction to send to controller immediately | ||
396 | + OFInstruction instr = factory.instructions() | ||
397 | + .buildApplyActions() | ||
398 | + .setActions(Collections.singletonList(outc)) | ||
399 | + .build(); | ||
400 | + instructions.add(instr); | ||
401 | + } | ||
402 | + | ||
403 | + if (toControllerWrite) { | ||
404 | + // table-miss instruction to write-action to send to controller | ||
405 | + // this will be executed whenever the action-set gets executed | ||
406 | + OFInstruction instr = factory.instructions() | ||
407 | + .buildWriteActions() | ||
408 | + .setActions(Collections.singletonList(outc)) | ||
409 | + .build(); | ||
410 | + instructions.add(instr); | ||
411 | + } | ||
412 | + | ||
413 | + if (toTable) { | ||
414 | + // table-miss instruction to goto-table x | ||
415 | + OFInstruction instr = factory.instructions() | ||
416 | + .gotoTable(TableId.of(tableToSend)); | ||
417 | + instructions.add(instr); | ||
418 | + } | ||
419 | + | ||
420 | + if (!toControllerNow && !toControllerWrite && !toTable) { | ||
421 | + // table-miss has no instruction - at which point action-set will be | ||
422 | + // executed - if there is an action to output/group in the action | ||
423 | + // set | ||
424 | + // the packet will be sent there, otherwise it will be dropped. | ||
425 | + instructions = (List<OFInstruction>) Collections.EMPTY_LIST; | ||
426 | + } | ||
427 | + | ||
428 | + OFMessage tableMissEntry = factory.buildFlowAdd() | ||
429 | + .setTableId(TableId.of(tableToAdd)) | ||
430 | + .setMatch(match) // match everything | ||
431 | + .setInstructions(instructions) | ||
432 | + .setPriority(MIN_PRIORITY) | ||
433 | + .setBufferId(OFBufferId.NO_BUFFER) | ||
434 | + .setIdleTimeout(0) | ||
435 | + .setHardTimeout(0) | ||
436 | + .setXid(getNextTransactionId()) | ||
437 | + .build(); | ||
438 | + write(tableMissEntry); | ||
439 | + } | ||
440 | + | ||
441 | + private void populateTableVlan() throws IOException { | ||
442 | + List<OFMessage> msglist = new ArrayList<OFMessage>(); | ||
443 | + for (OFPortDesc p : getPorts()) { | ||
444 | + int pnum = p.getPortNo().getPortNumber(); | ||
445 | + if (U32.of(pnum).compareTo(U32.of(OFPort.MAX.getPortNumber())) < 1) { | ||
446 | + OFOxmInPort oxp = factory.oxms().inPort(p.getPortNo()); | ||
447 | + OFOxmVlanVid oxv = factory.oxms() | ||
448 | + .vlanVid(OFVlanVidMatch.UNTAGGED); | ||
449 | + OFOxmList oxmList = OFOxmList.of(oxp, oxv); | ||
450 | + OFMatchV3 match = factory.buildMatchV3() | ||
451 | + .setOxmList(oxmList).build(); | ||
452 | + | ||
453 | + // TODO: match on vlan-tagged packets for vlans configured on | ||
454 | + // subnet ports and strip-vlan | ||
455 | + | ||
456 | + OFInstruction gotoTbl = factory.instructions().buildGotoTable() | ||
457 | + .setTableId(TableId.of(tmacTableId)).build(); | ||
458 | + List<OFInstruction> instructions = new ArrayList<OFInstruction>(); | ||
459 | + instructions.add(gotoTbl); | ||
460 | + OFMessage flowEntry = factory.buildFlowAdd() | ||
461 | + .setTableId(TableId.of(vlanTableId)) | ||
462 | + .setMatch(match) | ||
463 | + .setInstructions(instructions) | ||
464 | + .setPriority(1000) // does not matter - all rules | ||
465 | + // exclusive | ||
466 | + .setBufferId(OFBufferId.NO_BUFFER) | ||
467 | + .setIdleTimeout(0) | ||
468 | + .setHardTimeout(0) | ||
469 | + .setXid(getNextTransactionId()) | ||
470 | + .build(); | ||
471 | + msglist.add(flowEntry); | ||
472 | + } | ||
473 | + } | ||
474 | + write(msglist); | ||
475 | + log.debug("Adding {} port/vlan-rules in sw {}", msglist.size(), getStringId()); | ||
476 | + } | ||
477 | + | ||
478 | + private void populateTableTMac() throws IOException { | ||
479 | + // match for router-mac and ip-packets | ||
480 | + OFOxmEthType oxe = factory.oxms().ethType(EthType.IPv4); | ||
481 | + | ||
482 | + /* TODO: need to read network config and need to allow only | ||
483 | + the packets with DMAC as the correspondent router MAC address | ||
484 | + Until network configuration is implemented, all packets are allowed | ||
485 | + | ||
486 | + OFOxmEthDst dmac = factory.oxms().ethDst(getRouterMacAddr()); | ||
487 | + OFOxmList oxmListIp = OFOxmList.of(dmac, oxe); | ||
488 | + OFMatchV3 matchIp = factory.buildMatchV3() | ||
489 | + .setOxmList(oxmListIp).build(); | ||
490 | + */ | ||
491 | + OFOxmList oxmList = OFOxmList.EMPTY; | ||
492 | + OFMatchV3 matchIp = factory.buildMatchV3() | ||
493 | + .setOxmList(oxmList) | ||
494 | + .build(); | ||
495 | + | ||
496 | + OFInstruction gotoTblIp = factory.instructions().buildGotoTable() | ||
497 | + .setTableId(TableId.of(ipv4UnicastTableId)).build(); | ||
498 | + List<OFInstruction> instructionsIp = Collections.singletonList(gotoTblIp); | ||
499 | + OFMessage ipEntry = factory.buildFlowAdd() | ||
500 | + .setTableId(TableId.of(tmacTableId)) | ||
501 | + .setMatch(matchIp) | ||
502 | + .setInstructions(instructionsIp) | ||
503 | + .setPriority(1000) // strict priority required lower than | ||
504 | + // multicastMac | ||
505 | + .setBufferId(OFBufferId.NO_BUFFER) | ||
506 | + .setIdleTimeout(0) | ||
507 | + .setHardTimeout(0) | ||
508 | + .setXid(getNextTransactionId()) | ||
509 | + .build(); | ||
510 | + | ||
511 | + // match for router-mac and mpls packets | ||
512 | + OFOxmEthType oxmpls = factory.oxms().ethType(EthType.MPLS_UNICAST); | ||
513 | + /* TODO: need to read network config and need to allow only | ||
514 | + the packets with DMAC as the correspondent router MAC address | ||
515 | + OFOxmList oxmListMpls = OFOxmList.of(dmac, oxmpls); | ||
516 | + OFMatchV3 matchMpls = factory.buildMatchV3() | ||
517 | + .setOxmList(oxmListMpls).build(); | ||
518 | + */ | ||
519 | + OFOxmList oxmListMpls = OFOxmList.EMPTY; | ||
520 | + OFMatchV3 matchMpls = factory.buildMatchV3() | ||
521 | + .setOxmList(oxmList) | ||
522 | + .build(); | ||
523 | + | ||
524 | + OFInstruction gotoTblMpls = factory.instructions().buildGotoTable() | ||
525 | + .setTableId(TableId.of(mplsTableId)).build(); | ||
526 | + List<OFInstruction> instructionsMpls = Collections.singletonList(gotoTblMpls); | ||
527 | + OFMessage mplsEntry = factory.buildFlowAdd() | ||
528 | + .setTableId(TableId.of(tmacTableId)) | ||
529 | + .setMatch(matchMpls) | ||
530 | + .setInstructions(instructionsMpls) | ||
531 | + .setPriority(1001) // strict priority required lower than | ||
532 | + // multicastMac | ||
533 | + .setBufferId(OFBufferId.NO_BUFFER) | ||
534 | + .setIdleTimeout(0) | ||
535 | + .setHardTimeout(0) | ||
536 | + .setXid(getNextTransactionId()) | ||
537 | + .build(); | ||
538 | + | ||
539 | + log.debug("Adding termination-mac-rules in sw {}", getStringId()); | ||
540 | + List<OFMessage> msglist = new ArrayList<OFMessage>(2); | ||
541 | + msglist.add(ipEntry); | ||
542 | + msglist.add(mplsEntry); | ||
543 | + write(msglist); | ||
544 | + } | ||
545 | + | ||
546 | + private MacAddress getRouterMacAddr() { | ||
547 | + // TODO: need to read network config : RouterIp | ||
548 | + return MacAddress.of("00:00:00:00:00:00"); | ||
549 | + } | ||
550 | + | ||
551 | + private TableId getTableId(TableType tableType) { | ||
552 | + switch (tableType) { | ||
553 | + case IP: | ||
554 | + return TableId.of(ipv4UnicastTableId); | ||
555 | + case MPLS: | ||
556 | + return TableId.of(mplsTableId); | ||
557 | + case ACL: | ||
558 | + return TableId.of(aclTableId); | ||
559 | + default: { | ||
560 | + log.error("Table type {} is not supported in the driver", tableType); | ||
561 | + return TableId.NONE; | ||
562 | + } | ||
563 | + } | ||
564 | + } | ||
565 | + | ||
566 | + private void sendHandshakeBarrier() throws IOException { | ||
567 | + long xid = getNextTransactionId(); | ||
568 | + barrierXidToWaitFor = xid; | ||
569 | + OFBarrierRequest br = factory() | ||
570 | + .buildBarrierRequest() | ||
571 | + .setXid(xid) | ||
572 | + .build(); | ||
573 | + write(br); | ||
574 | + } | ||
63 | } | 575 | } |
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
... | @@ -166,8 +166,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -166,8 +166,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
166 | 166 | ||
167 | private void applyRule(FlowRule flowRule) { | 167 | private void applyRule(FlowRule flowRule) { |
168 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); | 168 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); |
169 | + if (flowRule.type() == FlowRule.Type.DEFAULT) { | ||
169 | sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), | 170 | sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), |
170 | Optional.empty()).buildFlowAdd()); | 171 | Optional.empty()).buildFlowAdd()); |
172 | + } else { | ||
173 | + sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), | ||
174 | + Optional.empty()).buildFlowAdd(), getTableType(flowRule.type())); | ||
175 | + } | ||
171 | } | 176 | } |
172 | 177 | ||
173 | 178 | ||
... | @@ -181,8 +186,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -181,8 +186,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
181 | 186 | ||
182 | private void removeRule(FlowRule flowRule) { | 187 | private void removeRule(FlowRule flowRule) { |
183 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); | 188 | OpenFlowSwitch sw = controller.getSwitch(Dpid.dpid(flowRule.deviceId().uri())); |
189 | + if (flowRule.type() == FlowRule.Type.DEFAULT) { | ||
184 | sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), | 190 | sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), |
185 | Optional.empty()).buildFlowDel()); | 191 | Optional.empty()).buildFlowDel()); |
192 | + } else { | ||
193 | + sw.sendMsg(FlowModBuilder.builder(flowRule, sw.factory(), | ||
194 | + Optional.empty()).buildFlowDel(), getTableType(flowRule.type())); | ||
195 | + } | ||
186 | } | 196 | } |
187 | 197 | ||
188 | @Override | 198 | @Override |
... | @@ -195,11 +205,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -195,11 +205,13 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
195 | public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { | 205 | public Future<CompletedBatchOperation> executeBatch(BatchOperation<FlowRuleBatchEntry> batch) { |
196 | final Set<Dpid> sws = Sets.newConcurrentHashSet(); | 206 | final Set<Dpid> sws = Sets.newConcurrentHashSet(); |
197 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>(); | 207 | final Map<Long, FlowRuleBatchEntry> fmXids = new HashMap<>(); |
208 | + | ||
198 | /* | 209 | /* |
199 | * Use identity hash map for reference equality as we could have equal | 210 | * Use identity hash map for reference equality as we could have equal |
200 | * flow mods for different switches. | 211 | * flow mods for different switches. |
201 | */ | 212 | */ |
202 | Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap(); | 213 | Map<OFFlowMod, OpenFlowSwitch> mods = Maps.newIdentityHashMap(); |
214 | + Map<OFFlowMod, OpenFlowSwitch.TableType> modTypes = Maps.newIdentityHashMap(); | ||
203 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { | 215 | for (FlowRuleBatchEntry fbe : batch.getOperations()) { |
204 | FlowRule flowRule = fbe.target(); | 216 | FlowRule flowRule = fbe.target(); |
205 | final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri()); | 217 | final Dpid dpid = Dpid.dpid(flowRule.deviceId().uri()); |
... | @@ -235,6 +247,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -235,6 +247,7 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
235 | } | 247 | } |
236 | if (mod != null) { | 248 | if (mod != null) { |
237 | mods.put(mod, sw); | 249 | mods.put(mod, sw); |
250 | + modTypes.put(mod, getTableType(flowRule.type())); | ||
238 | fmXids.put(flowModXid, fbe); | 251 | fmXids.put(flowModXid, fbe); |
239 | } else { | 252 | } else { |
240 | log.error("Conversion of flowrule {} failed.", flowRule); | 253 | log.error("Conversion of flowrule {} failed.", flowRule); |
... | @@ -249,12 +262,29 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr | ... | @@ -249,12 +262,29 @@ public class OpenFlowRuleProvider extends AbstractProvider implements FlowRulePr |
249 | for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) { | 262 | for (Map.Entry<OFFlowMod, OpenFlowSwitch> entry : mods.entrySet()) { |
250 | OpenFlowSwitch sw = entry.getValue(); | 263 | OpenFlowSwitch sw = entry.getValue(); |
251 | OFFlowMod mod = entry.getKey(); | 264 | OFFlowMod mod = entry.getKey(); |
265 | + OpenFlowSwitch.TableType tableType = modTypes.get(mod); | ||
266 | + if (tableType == OpenFlowSwitch.TableType.NONE) { | ||
252 | sw.sendMsg(mod); | 267 | sw.sendMsg(mod); |
268 | + } else { | ||
269 | + sw.sendMsg(mod, tableType); | ||
270 | + } | ||
253 | } | 271 | } |
254 | installation.verify(); | 272 | installation.verify(); |
255 | return installation; | 273 | return installation; |
256 | } | 274 | } |
257 | 275 | ||
276 | + private OpenFlowSwitch.TableType getTableType(FlowRule.Type type) { | ||
277 | + switch (type) { | ||
278 | + case IP: | ||
279 | + return OpenFlowSwitch.TableType.IP; | ||
280 | + case MPLS: | ||
281 | + return OpenFlowSwitch.TableType.MPLS; | ||
282 | + case ACL: | ||
283 | + return OpenFlowSwitch.TableType.ACL; | ||
284 | + default: | ||
285 | + return OpenFlowSwitch.TableType.NONE; | ||
286 | + } | ||
287 | + } | ||
258 | 288 | ||
259 | private class InternalFlowProvider | 289 | private class InternalFlowProvider |
260 | implements OpenFlowSwitchListener, OpenFlowEventListener { | 290 | implements OpenFlowSwitchListener, OpenFlowEventListener { | ... | ... |
-
Please register or login to post a comment