blob: 22312c1344e10459a26261f323964e433a405ddc [file] [log] [blame]
Umesh Krishnaswamy345ee992012-12-13 20:29:48 -08001/**
2 * Copyright 2011, Big Switch Networks, Inc.
3 * Originally created by David Erickson, Stanford University
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may
6 * not use this file except in compliance with the License. You may obtain
7 * a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations
15 * under the License.
16 **/
17
18package net.floodlightcontroller.routing;
19
20import java.io.IOException;
21import java.util.EnumSet;
22import java.util.ArrayList;
23import java.util.Comparator;
24import java.util.Iterator;
25import java.util.List;
26import java.util.Set;
27
28import net.floodlightcontroller.core.FloodlightContext;
29import net.floodlightcontroller.core.IFloodlightProviderService;
30import net.floodlightcontroller.core.IOFMessageListener;
31import net.floodlightcontroller.core.IOFSwitch;
32import net.floodlightcontroller.core.annotations.LogMessageCategory;
33import net.floodlightcontroller.core.annotations.LogMessageDoc;
34import net.floodlightcontroller.core.annotations.LogMessageDocs;
35import net.floodlightcontroller.core.util.AppCookie;
36import net.floodlightcontroller.counter.ICounterStoreService;
37import net.floodlightcontroller.devicemanager.IDevice;
38import net.floodlightcontroller.devicemanager.IDeviceListener;
39import net.floodlightcontroller.devicemanager.IDeviceService;
40import net.floodlightcontroller.devicemanager.SwitchPort;
41import net.floodlightcontroller.packet.Ethernet;
42import net.floodlightcontroller.packet.IPacket;
43import net.floodlightcontroller.routing.IRoutingService;
44import net.floodlightcontroller.routing.IRoutingDecision;
45import net.floodlightcontroller.routing.Route;
46import net.floodlightcontroller.topology.ITopologyService;
47import net.floodlightcontroller.topology.NodePortTuple;
48import net.floodlightcontroller.util.OFMessageDamper;
49import net.floodlightcontroller.util.TimedCache;
50
51import org.openflow.protocol.OFFlowMod;
52import org.openflow.protocol.OFMatch;
53import org.openflow.protocol.OFMessage;
54import org.openflow.protocol.OFPacketIn;
55import org.openflow.protocol.OFPacketOut;
56import org.openflow.protocol.OFType;
57import org.openflow.protocol.action.OFAction;
58import org.openflow.protocol.action.OFActionOutput;
59import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
62/**
63 * Abstract base class for implementing a forwarding module. Forwarding is
64 * responsible for programming flows to a switch in response to a policy
65 * decision.
66 */
67@LogMessageCategory("Flow Programming")
68public abstract class ForwardingBase
69 implements IOFMessageListener, IDeviceListener {
70
71 protected static Logger log =
72 LoggerFactory.getLogger(ForwardingBase.class);
73
74 protected static int OFMESSAGE_DAMPER_CAPACITY = 50000; // TODO: find sweet spot
75 protected static int OFMESSAGE_DAMPER_TIMEOUT = 250; // ms
76
77 public static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
78 public static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
79
80 protected IFloodlightProviderService floodlightProvider;
81 protected IDeviceService deviceManager;
82 protected IRoutingService routingEngine;
83 protected ITopologyService topology;
84 protected ICounterStoreService counterStore;
85
86 protected OFMessageDamper messageDamper;
87
88 // for broadcast loop suppression
89 protected boolean broadcastCacheFeature = true;
90 public final int prime1 = 2633; // for hash calculation
91 public final static int prime2 = 4357; // for hash calculation
92 public TimedCache<Long> broadcastCache =
93 new TimedCache<Long>(100, 5*1000); // 5 seconds interval;
94
95 // flow-mod - for use in the cookie
96 public static final int FORWARDING_APP_ID = 2; // TODO: This must be managed
97 // by a global APP_ID class
98 public long appCookie = AppCookie.makeCookie(FORWARDING_APP_ID, 0);
99
100 // Comparator for sorting by SwitchCluster
101 public Comparator<SwitchPort> clusterIdComparator =
102 new Comparator<SwitchPort>() {
103 @Override
104 public int compare(SwitchPort d1, SwitchPort d2) {
105 Long d1ClusterId =
106 topology.getL2DomainId(d1.getSwitchDPID());
107 Long d2ClusterId =
108 topology.getL2DomainId(d2.getSwitchDPID());
109 return d1ClusterId.compareTo(d2ClusterId);
110 }
111 };
112
113 /**
114 * init data structures
115 *
116 */
117 protected void init() {
118 messageDamper = new OFMessageDamper(OFMESSAGE_DAMPER_CAPACITY,
119 EnumSet.of(OFType.FLOW_MOD),
120 OFMESSAGE_DAMPER_TIMEOUT);
121 }
122
123 /**
124 * Adds a listener for devicemanager and registers for PacketIns.
125 */
126 protected void startUp() {
127 deviceManager.addListener(this);
128 floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this);
129 }
130
131 /**
132 * Returns the application name "forwarding".
133 */
134 @Override
135 public String getName() {
136 return "forwarding";
137 }
138
139 /**
140 * All subclasses must define this function if they want any specific
141 * forwarding action
142 *
143 * @param sw
144 * Switch that the packet came in from
145 * @param pi
146 * The packet that came in
147 * @param decision
148 * Any decision made by a policy engine
149 */
150 public abstract Command
151 processPacketInMessage(IOFSwitch sw, OFPacketIn pi,
152 IRoutingDecision decision,
153 FloodlightContext cntx);
154
155 @Override
156 public Command receive(IOFSwitch sw, OFMessage msg,
157 FloodlightContext cntx) {
158 switch (msg.getType()) {
159 case PACKET_IN:
160 IRoutingDecision decision = null;
161 if (cntx != null)
162 decision =
163 IRoutingDecision.rtStore.get(cntx,
164 IRoutingDecision.CONTEXT_DECISION);
165
166 return this.processPacketInMessage(sw,
167 (OFPacketIn) msg,
168 decision,
169 cntx);
170 default:
171 break;
172 }
173 return Command.CONTINUE;
174 }
175
176 /**
177 * Push routes from back to front
178 * @param route Route to push
179 * @param match OpenFlow fields to match on
180 * @param srcSwPort Source switch port for the first hop
181 * @param dstSwPort Destination switch port for final hop
182 * @param cookie The cookie to set in each flow_mod
183 * @param cntx The floodlight context
184 * @param reqeustFlowRemovedNotifn if set to true then the switch would
185 * send a flow mod removal notification when the flow mod expires
186 * @param doFlush if set to true then the flow mod would be immediately
187 * written to the switch
188 * @param flowModCommand flow mod. command to use, e.g. OFFlowMod.OFPFC_ADD,
189 * OFFlowMod.OFPFC_MODIFY etc.
190 * @return srcSwitchIincluded True if the source switch is included in this route
191 */
192 @LogMessageDocs({
193 @LogMessageDoc(level="WARN",
194 message="Unable to push route, switch at DPID {dpid} not available",
195 explanation="A switch along the calculated path for the " +
196 "flow has disconnected.",
197 recommendation=LogMessageDoc.CHECK_SWITCH),
198 @LogMessageDoc(level="ERROR",
199 message="Failure writing flow mod",
200 explanation="An I/O error occurred while writing a " +
201 "flow modification to a switch",
202 recommendation=LogMessageDoc.CHECK_SWITCH)
203 })
204 public boolean pushRoute(Route route, OFMatch match,
205 Integer wildcard_hints,
206 OFPacketIn pi,
207 long pinSwitch,
208 long cookie,
209 FloodlightContext cntx,
210 boolean reqeustFlowRemovedNotifn,
211 boolean doFlush,
212 short flowModCommand) {
213
214 boolean srcSwitchIncluded = false;
215 OFFlowMod fm =
216 (OFFlowMod) floodlightProvider.getOFMessageFactory()
217 .getMessage(OFType.FLOW_MOD);
218 OFActionOutput action = new OFActionOutput();
219 action.setMaxLength((short)0xffff);
220 List<OFAction> actions = new ArrayList<OFAction>();
221 actions.add(action);
222
223 fm.setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
224 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
225 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
226 .setCookie(cookie)
227 .setCommand(flowModCommand)
228 .setMatch(match)
229 .setActions(actions)
230 .setLengthU(OFFlowMod.MINIMUM_LENGTH+OFActionOutput.MINIMUM_LENGTH);
231
232 List<NodePortTuple> switchPortList = route.getPath();
233
234 for (int indx = switchPortList.size()-1; indx > 0; indx -= 2) {
235 // indx and indx-1 will always have the same switch DPID.
236 long switchDPID = switchPortList.get(indx).getNodeId();
237 IOFSwitch sw = floodlightProvider.getSwitches().get(switchDPID);
238 if (sw == null) {
239 if (log.isWarnEnabled()) {
240 log.warn("Unable to push route, switch at DPID {} " +
241 "not available", switchDPID);
242 }
243 return srcSwitchIncluded;
244 }
245
246 // set the match.
247 fm.setMatch(wildcard(match, sw, wildcard_hints));
248
249 // set buffer id if it is the source switch
250 if (1 == indx) {
251 // Set the flag to request flow-mod removal notifications only for the
252 // source switch. The removal message is used to maintain the flow
253 // cache. Don't set the flag for ARP messages - TODO generalize check
254 if ((reqeustFlowRemovedNotifn)
255 && (match.getDataLayerType() != Ethernet.TYPE_ARP)) {
256 fm.setFlags(OFFlowMod.OFPFF_SEND_FLOW_REM);
257 match.setWildcards(fm.getMatch().getWildcards());
258 }
259 }
260
261 short outPort = switchPortList.get(indx).getPortId();
262 short inPort = switchPortList.get(indx-1).getPortId();
263 // set input and output ports on the switch
264 fm.getMatch().setInputPort(inPort);
265 ((OFActionOutput)fm.getActions().get(0)).setPort(outPort);
266
267 try {
268 counterStore.updatePktOutFMCounterStore(sw, fm);
269 if (log.isTraceEnabled()) {
270 log.trace("Pushing Route flowmod routeIndx={} " +
271 "sw={} inPort={} outPort={}",
272 new Object[] {indx,
273 sw,
274 fm.getMatch().getInputPort(),
275 outPort });
276 }
277 messageDamper.write(sw, fm, cntx);
278 if (doFlush) {
279 sw.flush();
280 }
281
282 // Push the packet out the source switch
283 if (sw.getId() == pinSwitch) {
284 // TODO: Instead of doing a packetOut here we could also
285 // send a flowMod with bufferId set....
286 pushPacket(sw, match, pi, outPort, cntx);
287 srcSwitchIncluded = true;
288 }
289 } catch (IOException e) {
290 log.error("Failure writing flow mod", e);
291 }
292
293 try {
294 fm = fm.clone();
295 } catch (CloneNotSupportedException e) {
296 log.error("Failure cloning flow mod", e);
297 }
298 }
299
300 return srcSwitchIncluded;
301 }
302
303 protected OFMatch wildcard(OFMatch match, IOFSwitch sw,
304 Integer wildcard_hints) {
305 if (wildcard_hints != null) {
306 return match.clone().setWildcards(wildcard_hints.intValue());
307 }
308 return match.clone();
309 }
310
311 /**
312 * Pushes a packet-out to a switch. If bufferId != BUFFER_ID_NONE we
313 * assume that the packetOut switch is the same as the packetIn switch
314 * and we will use the bufferId
315 * Caller needs to make sure that inPort and outPort differs
316 * @param packet packet data to send
317 * @param sw switch from which packet-out is sent
318 * @param bufferId bufferId
319 * @param inPort input port
320 * @param outPort output port
321 * @param cntx context of the packet
322 * @param flush force to flush the packet.
323 */
324 @LogMessageDocs({
325 @LogMessageDoc(level="ERROR",
326 message="BufferId is not and packet data is null. " +
327 "Cannot send packetOut. " +
328 "srcSwitch={dpid} inPort={port} outPort={port}",
329 explanation="The switch send a malformed packet-in." +
330 "The packet will be dropped",
331 recommendation=LogMessageDoc.REPORT_SWITCH_BUG),
332 @LogMessageDoc(level="ERROR",
333 message="Failure writing packet out",
334 explanation="An I/O error occurred while writing a " +
335 "packet out to a switch",
336 recommendation=LogMessageDoc.CHECK_SWITCH)
337 })
338 public void pushPacket(IPacket packet,
339 IOFSwitch sw,
340 int bufferId,
341 short inPort,
342 short outPort,
343 FloodlightContext cntx,
344 boolean flush) {
345
346
347 if (log.isTraceEnabled()) {
348 log.trace("PacketOut srcSwitch={} inPort={} outPort={}",
349 new Object[] {sw, inPort, outPort});
350 }
351
352 OFPacketOut po =
353 (OFPacketOut) floodlightProvider.getOFMessageFactory()
354 .getMessage(OFType.PACKET_OUT);
355
356 // set actions
357 List<OFAction> actions = new ArrayList<OFAction>();
358 actions.add(new OFActionOutput(outPort, (short) 0xffff));
359
360 po.setActions(actions)
361 .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
362 short poLength =
363 (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
364
365 // set buffer_id, in_port
366 po.setBufferId(bufferId);
367 po.setInPort(inPort);
368
369 // set data - only if buffer_id == -1
370 if (po.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
371 if (packet == null) {
372 log.error("BufferId is not set and packet data is null. " +
373 "Cannot send packetOut. " +
374 "srcSwitch={} inPort={} outPort={}",
375 new Object[] {sw, inPort, outPort});
376 return;
377 }
378 byte[] packetData = packet.serialize();
379 poLength += packetData.length;
380 po.setPacketData(packetData);
381 }
382
383 po.setLength(poLength);
384
385 try {
386 counterStore.updatePktOutFMCounterStore(sw, po);
387 messageDamper.write(sw, po, cntx, flush);
388 } catch (IOException e) {
389 log.error("Failure writing packet out", e);
390 }
391 }
392
393 /**
394 * Pushes a packet-out to a switch. The assumption here is that
395 * the packet-in was also generated from the same switch. Thus, if the input
396 * port of the packet-in and the outport are the same, the function will not
397 * push the packet-out.
398 * @param sw switch that generated the packet-in, and from which packet-out is sent
399 * @param match OFmatch
400 * @param pi packet-in
401 * @param outport output port
402 * @param cntx context of the packet
403 */
404 protected void pushPacket(IOFSwitch sw, OFMatch match, OFPacketIn pi,
405 short outport, FloodlightContext cntx) {
406
407 if (pi == null) {
408 return;
409 } else if (pi.getInPort() == outport){
410 log.warn("Packet out not sent as the outport matches inport. {}",
411 pi);
412 return;
413 }
414
415 // The assumption here is (sw) is the switch that generated the
416 // packet-in. If the input port is the same as output port, then
417 // the packet-out should be ignored.
418 if (pi.getInPort() == outport) {
419 if (log.isDebugEnabled()) {
420 log.debug("Attempting to do packet-out to the same " +
421 "interface as packet-in. Dropping packet. " +
422 " SrcSwitch={}, match = {}, pi={}",
423 new Object[]{sw, match, pi});
424 return;
425 }
426 }
427
428 if (log.isTraceEnabled()) {
429 log.trace("PacketOut srcSwitch={} match={} pi={}",
430 new Object[] {sw, match, pi});
431 }
432
433 OFPacketOut po =
434 (OFPacketOut) floodlightProvider.getOFMessageFactory()
435 .getMessage(OFType.PACKET_OUT);
436
437 // set actions
438 List<OFAction> actions = new ArrayList<OFAction>();
439 actions.add(new OFActionOutput(outport, (short) 0xffff));
440
441 po.setActions(actions)
442 .setActionsLength((short) OFActionOutput.MINIMUM_LENGTH);
443 short poLength =
444 (short) (po.getActionsLength() + OFPacketOut.MINIMUM_LENGTH);
445
446 // If the switch doens't support buffering set the buffer id to be none
447 // otherwise it'll be the the buffer id of the PacketIn
448 if (sw.getBuffers() == 0) {
449 // We set the PI buffer id here so we don't have to check again below
450 pi.setBufferId(OFPacketOut.BUFFER_ID_NONE);
451 po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
452 } else {
453 po.setBufferId(pi.getBufferId());
454 }
455
456 po.setInPort(pi.getInPort());
457
458 // If the buffer id is none or the switch doesn's support buffering
459 // we send the data with the packet out
460 if (pi.getBufferId() == OFPacketOut.BUFFER_ID_NONE) {
461 byte[] packetData = pi.getPacketData();
462 poLength += packetData.length;
463 po.setPacketData(packetData);
464 }
465
466 po.setLength(poLength);
467
468 try {
469 counterStore.updatePktOutFMCounterStore(sw, po);
470 messageDamper.write(sw, po, cntx);
471 } catch (IOException e) {
472 log.error("Failure writing packet out", e);
473 }
474 }
475
476
477 /**
478 * Write packetout message to sw with output actions to one or more
479 * output ports with inPort/outPorts passed in.
480 * @param packetData
481 * @param sw
482 * @param inPort
483 * @param ports
484 * @param cntx
485 */
486 public void packetOutMultiPort(byte[] packetData,
487 IOFSwitch sw,
488 short inPort,
489 Set<Integer> outPorts,
490 FloodlightContext cntx) {
491 //setting actions
492 List<OFAction> actions = new ArrayList<OFAction>();
493
494 Iterator<Integer> j = outPorts.iterator();
495
496 while (j.hasNext())
497 {
498 actions.add(new OFActionOutput(j.next().shortValue(),
499 (short) 0));
500 }
501
502 OFPacketOut po =
503 (OFPacketOut) floodlightProvider.getOFMessageFactory().
504 getMessage(OFType.PACKET_OUT);
505 po.setActions(actions);
506 po.setActionsLength((short) (OFActionOutput.MINIMUM_LENGTH *
507 outPorts.size()));
508
509 // set buffer-id to BUFFER_ID_NONE, and set in-port to OFPP_NONE
510 po.setBufferId(OFPacketOut.BUFFER_ID_NONE);
511 po.setInPort(inPort);
512
513 // data (note buffer_id is always BUFFER_ID_NONE) and length
514 short poLength = (short)(po.getActionsLength() +
515 OFPacketOut.MINIMUM_LENGTH);
516 poLength += packetData.length;
517 po.setPacketData(packetData);
518 po.setLength(poLength);
519
520 try {
521 counterStore.updatePktOutFMCounterStore(sw, po);
522 if (log.isTraceEnabled()) {
523 log.trace("write broadcast packet on switch-id={} " +
524 "interfaces={} packet-out={}",
525 new Object[] {sw.getId(), outPorts, po});
526 }
527 messageDamper.write(sw, po, cntx);
528
529 } catch (IOException e) {
530 log.error("Failure writing packet out", e);
531 }
532 }
533
534 /**
535 * @see packetOutMultiPort
536 * Accepts a PacketIn instead of raw packet data. Note that the inPort
537 * and switch can be different than the packet in switch/port
538 */
539 public void packetOutMultiPort(OFPacketIn pi,
540 IOFSwitch sw,
541 short inPort,
542 Set<Integer> outPorts,
543 FloodlightContext cntx) {
544 packetOutMultiPort(pi.getPacketData(), sw, inPort, outPorts, cntx);
545 }
546
547 /**
548 * @see packetOutMultiPort
549 * Accepts an IPacket instead of raw packet data. Note that the inPort
550 * and switch can be different than the packet in switch/port
551 */
552 public void packetOutMultiPort(IPacket packet,
553 IOFSwitch sw,
554 short inPort,
555 Set<Integer> outPorts,
556 FloodlightContext cntx) {
557 packetOutMultiPort(packet.serialize(), sw, inPort, outPorts, cntx);
558 }
559
560 protected boolean isInBroadcastCache(IOFSwitch sw, OFPacketIn pi,
561 FloodlightContext cntx) {
562 // Get the cluster id of the switch.
563 // Get the hash of the Ethernet packet.
564 if (sw == null) return true;
565
566 // If the feature is disabled, always return false;
567 if (!broadcastCacheFeature) return false;
568
569 Ethernet eth =
570 IFloodlightProviderService.bcStore.get(cntx,
571 IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
572
573 Long broadcastHash;
574 broadcastHash = topology.getL2DomainId(sw.getId()) * prime1 +
575 pi.getInPort() * prime2 + eth.hashCode();
576 if (broadcastCache.update(broadcastHash)) {
577 sw.updateBroadcastCache(broadcastHash, pi.getInPort());
578 return true;
579 } else {
580 return false;
581 }
582 }
583
584 protected boolean isInSwitchBroadcastCache(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx) {
585 if (sw == null) return true;
586
587 // If the feature is disabled, always return false;
588 if (!broadcastCacheFeature) return false;
589
590 // Get the hash of the Ethernet packet.
591 Ethernet eth =
592 IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
593
594 long hash = pi.getInPort() * prime2 + eth.hashCode();
595
596 // some FORWARD_OR_FLOOD packets are unicast with unknown destination mac
597 return sw.updateBroadcastCache(hash, pi.getInPort());
598 }
599
600 @LogMessageDocs({
601 @LogMessageDoc(level="ERROR",
602 message="Failure writing deny flow mod",
603 explanation="An I/O error occurred while writing a " +
604 "deny flow mod to a switch",
605 recommendation=LogMessageDoc.CHECK_SWITCH)
606 })
607 public static boolean
608 blockHost(IFloodlightProviderService floodlightProvider,
609 SwitchPort sw_tup, long host_mac,
610 short hardTimeout, long cookie) {
611
612 if (sw_tup == null) {
613 return false;
614 }
615
616 IOFSwitch sw =
617 floodlightProvider.getSwitches().get(sw_tup.getSwitchDPID());
618 if (sw == null) return false;
619 int inputPort = sw_tup.getPort();
620 log.debug("blockHost sw={} port={} mac={}",
621 new Object[] { sw, sw_tup.getPort(), new Long(host_mac) });
622
623 // Create flow-mod based on packet-in and src-switch
624 OFFlowMod fm =
625 (OFFlowMod) floodlightProvider.getOFMessageFactory()
626 .getMessage(OFType.FLOW_MOD);
627 OFMatch match = new OFMatch();
628 List<OFAction> actions = new ArrayList<OFAction>(); // Set no action to
629 // drop
630 match.setDataLayerSource(Ethernet.toByteArray(host_mac))
631 .setInputPort((short)inputPort)
632 .setWildcards(OFMatch.OFPFW_ALL & ~OFMatch.OFPFW_DL_SRC
633 & ~OFMatch.OFPFW_IN_PORT);
634 fm.setCookie(cookie)
635 .setHardTimeout((short) hardTimeout)
636 .setIdleTimeout(FLOWMOD_DEFAULT_IDLE_TIMEOUT)
637 .setHardTimeout(FLOWMOD_DEFAULT_HARD_TIMEOUT)
638 .setBufferId(OFPacketOut.BUFFER_ID_NONE)
639 .setMatch(match)
640 .setActions(actions)
641 .setLengthU(OFFlowMod.MINIMUM_LENGTH); // +OFActionOutput.MINIMUM_LENGTH);
642
643 try {
644 log.debug("write drop flow-mod sw={} match={} flow-mod={}",
645 new Object[] { sw, match, fm });
646 // TODO: can't use the message damper sine this method is static
647 sw.write(fm, null);
648 } catch (IOException e) {
649 log.error("Failure writing deny flow mod", e);
650 return false;
651 }
652 return true;
653
654 }
655
656 @Override
657 public void deviceAdded(IDevice device) {
658 // NOOP
659 }
660
661 @Override
662 public void deviceRemoved(IDevice device) {
663 // NOOP
664 }
665
666 @Override
667 public void deviceMoved(IDevice device) {
668 }
669
670 @Override
671 public void deviceIPV4AddrChanged(IDevice device) {
672
673 }
674
675 @Override
676 public void deviceVlanChanged(IDevice device) {
677
678 }
679
680 @Override
681 public boolean isCallbackOrderingPrereq(OFType type, String name) {
682 return (type.equals(OFType.PACKET_IN) &&
683 (name.equals("topology") ||
684 name.equals("devicemanager")));
685 }
686
687 @Override
688 public boolean isCallbackOrderingPostreq(OFType type, String name) {
689 return false;
690 }
691
692}