sangho
Committed by Jonathan Hart

Added SpringOpenTTP switch driver (ONOS-822/ONOS-682).

Modified OpenFlpwRuleProvider to support FlowRule with multiple-table feature.

Change-Id: If95284077b96213593c5c1e3ab12900001bf49a2
...@@ -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 {
......