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