· 7 years ago · Dec 10, 2018, 08:48 PM
1package net.floodlightcontroller.cgrmodule;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.Collections;
6import java.util.HashMap;
7import java.util.HashSet;
8import java.util.Iterator;
9import java.util.List;
10import java.util.Map;
11import java.util.Map.Entry;
12import java.util.Set;
13import java.util.concurrent.ConcurrentHashMap;
14
15import org.projectfloodlight.openflow.protocol.OFFlowMod;
16import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
17import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
18import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
19import org.projectfloodlight.openflow.protocol.OFMessage;
20import org.projectfloodlight.openflow.protocol.OFPacketIn;
21import org.projectfloodlight.openflow.protocol.OFPacketOut;
22import org.projectfloodlight.openflow.protocol.OFType;
23import org.projectfloodlight.openflow.protocol.OFVersion;
24import org.projectfloodlight.openflow.protocol.action.OFAction;
25import org.projectfloodlight.openflow.protocol.action.OFActionOutput;
26import org.projectfloodlight.openflow.protocol.action.OFActions;
27import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
28import org.projectfloodlight.openflow.protocol.instruction.OFInstructionApplyActions;
29import org.projectfloodlight.openflow.protocol.instruction.OFInstructions;
30import org.projectfloodlight.openflow.protocol.match.Match;
31import org.projectfloodlight.openflow.protocol.match.MatchField;
32import org.projectfloodlight.openflow.types.EthType;
33import org.projectfloodlight.openflow.types.IPv4Address;
34import org.projectfloodlight.openflow.types.IpProtocol;
35import org.projectfloodlight.openflow.types.MacAddress;
36import org.projectfloodlight.openflow.types.OFBufferId;
37import org.projectfloodlight.openflow.types.OFPort;
38import org.projectfloodlight.openflow.types.OFVlanVidMatch;
39import org.projectfloodlight.openflow.types.TableId;
40import org.projectfloodlight.openflow.types.TransportPort;
41import org.projectfloodlight.openflow.types.U64;
42import org.projectfloodlight.openflow.types.VlanVid;
43import org.projectfloodlight.openflow.util.LRULinkedHashMap;
44import org.slf4j.Logger;
45import org.slf4j.LoggerFactory;
46
47import javafx.util.Pair;
48import net.floodlightcontroller.cgrmodule.util.*;
49import net.floodlightcontroller.core.FloodlightContext;
50import net.floodlightcontroller.core.IControllerCompletionListener;
51import net.floodlightcontroller.core.IFloodlightProviderService;
52import net.floodlightcontroller.core.IOFMessageListener;
53import net.floodlightcontroller.core.IOFSwitch;
54import net.floodlightcontroller.core.module.FloodlightModuleContext;
55import net.floodlightcontroller.core.module.FloodlightModuleException;
56import net.floodlightcontroller.core.module.IFloodlightModule;
57import net.floodlightcontroller.core.module.IFloodlightService;
58import net.floodlightcontroller.learningswitch.LearningSwitch;
59import net.floodlightcontroller.packet.Ethernet;
60import net.floodlightcontroller.packet.IPv4;
61import net.floodlightcontroller.packet.TCP;
62import net.floodlightcontroller.util.OFMessageUtils;
63
64public class CGRmodule implements IFloodlightModule, IOFMessageListener {
65 protected static Logger log = LoggerFactory.getLogger(CGRmodule.class);
66
67 // Module dependencies
68 protected IFloodlightProviderService floodlightProviderService;
69
70 // Stores the learned state for each switch
71 protected Map<IOFSwitch, Map<MacAddress, OFPort>> ControllerMap;
72
73 // Stores the number of connections for a given MAC address.
74 protected Map<Pair<IPv4Address,TransportPort>, Integer> TCPLinkCounterMap;
75
76 // flow-mod - for use in the cookie
77 public static final int LEARNING_SWITCH_APP_ID = 1;
78 // LOOK! This should probably go in some class that encapsulates
79 // the app cookie management
80 public static final int APP_ID_BITS = 12;
81 public static final int APP_ID_SHIFT = (64 - APP_ID_BITS);
82 public static final long LEARNING_SWITCH_COOKIE = (long) (LEARNING_SWITCH_APP_ID & ((1 << APP_ID_BITS) - 1)) << APP_ID_SHIFT;
83
84 // more flow-mod defaults
85 protected static short FLOWMOD_DEFAULT_IDLE_TIMEOUT = 5; // in seconds
86 protected static short FLOWMOD_DEFAULT_HARD_TIMEOUT = 0; // infinite
87 protected static short FLOWMOD_PRIORITY = 100;
88 protected static short DEFAULT_PRIORITY = 10;
89
90 // for managing our map sizes
91 protected static final int MAX_MACS_PER_SWITCH = 1000;
92
93 // CGR Firewall module
94 protected static final int MAX_DESTINATION_NUMBER = 3;
95 protected static final int MAX_ELEPHANT_FLOWS = 3;
96 protected static final int ELEPHANT_FLOW_BW = 10;
97
98 // normally, setup reverse flow as well. Disable only for using cbench for comparison with NOX etc.
99 protected static final boolean LEARNING_SWITCH_REVERSE_FLOW = true;
100
101 /**
102 * @param floodlightProvider the floodlightProvider to set
103 */
104 public void setFloodlightProvider(IFloodlightProviderService floodlightProviderService) {
105 this.floodlightProviderService = floodlightProviderService;
106 }
107
108 @Override
109 public String getName() {
110 return "CGRModule";
111 }
112
113 /**
114 * Adds a host to the MAC->SwitchPort mapping
115 * @param sw The switch to add the mapping to
116 * @param mac The MAC address of the host to add
117 * @param portVal The switchport that the host is on
118 */
119 protected void addToPortMap(IOFSwitch sw, MacAddress mac, OFPort portVal)
120 {
121 Map<MacAddress, OFPort> swMap = ControllerMap.get(sw);
122
123 // Check if the switch already exists
124 if (swMap == null) {
125 swMap = new LRULinkedHashMap<MacAddress, OFPort>(MAX_MACS_PER_SWITCH);
126 ControllerMap.put(sw, swMap);
127 }
128
129 if ( swMap.putIfAbsent(mac, portVal) != portVal) {
130 swMap.replace(mac, portVal);
131 log.info( "Sw: " + sw
132 + " --- New PortMAC: "
133 + " MAC {} PORT {}",
134 new Object[]{ mac.toString(),
135 portVal});
136 }
137 }
138
139 /**
140 * Removes a host from the MAC->SwitchPort mapping
141 * @param sw The switch to remove the mapping from
142 * @param mac The MAC address of the host to remove
143 */
144 protected void removeFromPortMap(IOFSwitch sw, MacAddress mac) {
145
146 Map<MacAddress, OFPort> swMap = ControllerMap.get(sw);
147 if (swMap != null) {
148 swMap.remove(mac);
149 log.info( "Sw: " + sw
150 + " --- Removed PortMAC: "
151 + " MAC {}",
152 new Object[]{ mac.toString()});
153 }
154 }
155
156 /**
157 * Get the port that a MAC is associated with
158 * @param sw The switch to get the mapping from
159 * @param mac The MAC address to get
160 * @return The port the host is on
161 */
162 public OFPort getFromPortMap(IOFSwitch sw, MacAddress mac) {
163 Map<MacAddress, OFPort> swMap = ControllerMap.get(sw);
164 if (swMap != null) {
165 return swMap.get(mac);
166 }
167
168 // if none found
169 return null;
170 }
171
172 /**
173 * Clears the MAC -> SwitchPort map for all switches
174 */
175 public void clearLearnedTable() {
176 ControllerMap.clear();
177 }
178
179 /**
180 * Clears the MAC/VLAN -> SwitchPort map for a single switch
181 * @param sw The switch to clear the mapping for
182 */
183 public void clearLearnedTable(IOFSwitch sw) {
184 Map<MacAddress, OFPort> swMap = ControllerMap.get(sw);
185 if (swMap != null) {
186 swMap.clear();
187 }
188 }
189
190 protected Match createMatchFromPacket(IOFSwitch sw, OFPort inPort, FloodlightContext cntx)
191 {
192 // The packet in match will only contain the port number.
193 // We need to add in specifics for the hosts we're routing between.
194 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
195 MacAddress srcMac = eth.getSourceMACAddress();
196 MacAddress dstMac = eth.getDestinationMACAddress();
197
198 Match.Builder mb = sw.getOFFactory().buildMatch();
199 mb.setExact(MatchField.IN_PORT, inPort)
200 .setExact(MatchField.ETH_SRC, srcMac)
201 .setExact(MatchField.ETH_DST, dstMac);
202 //.setExact(MatchField.TCP_DST)
203 return mb.build();
204 }
205
206 protected Match createMatchFromTCPPacket(IOFSwitch sw, OFPort inPort, FloodlightContext cntx)
207 {
208 // The packet in match will only contain the port number.
209 // We need to add in specifics for the hosts we're routing between.
210 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
211 MacAddress srcMac = eth.getSourceMACAddress();
212 MacAddress dstMac = eth.getDestinationMACAddress();
213
214 if ( eth.getEtherType() == EthType.IPv4 )
215 {
216 IPv4 ipv4 = (IPv4) eth.getPayload();
217 IPv4Address ipv4Src = ipv4.getSourceAddress();
218 IPv4Address ipv4Dest = ipv4.getDestinationAddress();
219
220 if ( ipv4.getProtocol() == IpProtocol.TCP )
221 {
222 TCP tcp = (TCP) ipv4.getPayload();
223 TransportPort portSrc = tcp.getSourcePort();
224 TransportPort portDest = tcp.getDestinationPort();
225
226 Match.Builder mb = sw.getOFFactory().buildMatch();
227 mb.setExact(MatchField.IN_PORT, inPort)
228 .setExact(MatchField.ETH_SRC, srcMac)
229 .setExact(MatchField.ETH_DST, dstMac)
230 .setExact(MatchField.IPV4_SRC, ipv4Src)
231 .setExact(MatchField.IPV4_DST, ipv4Dest)
232 .setExact(MatchField.TCP_DST, portDest)
233 .setExact(MatchField.TCP_SRC, portSrc);
234 return mb.build();
235 } // End of TCP
236 } // End of IPv4
237 return null;
238 }
239
240 protected Match createReverseMatchfromMatch(IOFSwitch sw, OFPort outPort, Match match)
241 {
242 Match.Builder rev_match = match.createBuilder();
243 rev_match.setExact(MatchField.IN_PORT, outPort)
244 .setExact(MatchField.ETH_SRC, match.get(MatchField.ETH_DST))
245 .setExact(MatchField.ETH_DST, match.get(MatchField.ETH_SRC));
246 return rev_match.build();
247 }
248
249 protected Match createReverseMatchfromMatch(IOFSwitch sw, Match match)
250 {
251 Match.Builder rev_match = match.createBuilder();
252 rev_match.setExact(MatchField.ETH_SRC, match.get(MatchField.ETH_DST))
253 .setExact(MatchField.ETH_DST, match.get(MatchField.ETH_SRC));
254
255 return rev_match.build();
256 }
257
258 protected void createFlowMod(IOFSwitch sw, OFPort Port, Match match, OFVersion version, short prio, Boolean remFlag)
259 {
260 // Action List
261 List<OFAction> al = new ArrayList<OFAction>();
262 OFActionOutput output = sw.getOFFactory().actions().buildOutput()
263 .setPort(Port) // outPort is the port trough which the sw should send the Matching Packets
264 .setMaxLen(0xffFFffFF)
265 .build();
266 al.add(output);
267
268
269 // Write the flow mod using SwitchCommands install rule method since it receives either instructions or actions
270 // depending on the OpenFlow Version you should do the following:
271 if (version.compareTo(OFVersion.OF_13) == 0 )
272 {
273 OFInstructionApplyActions applyActions = sw.getOFFactory().instructions().buildApplyActions().setActions(al).build(); //use the instructions builder to build an applyActions instruction with the given action list.
274 ArrayList<OFInstruction> instructionList = new ArrayList<OFInstruction>();
275 instructionList.add(applyActions); //add the applyActions Instruction to the Instruction list
276 SwitchCommands.installRule(sw, TableId.of(0), prio, match, instructionList, null, CGRmodule.FLOWMOD_DEFAULT_HARD_TIMEOUT, CGRmodule.FLOWMOD_DEFAULT_IDLE_TIMEOUT, OFBufferId.NO_BUFFER, remFlag);
277
278 } else {
279 SwitchCommands.installRule(sw, null, prio, match, null, al, CGRmodule.FLOWMOD_DEFAULT_HARD_TIMEOUT, CGRmodule.FLOWMOD_DEFAULT_IDLE_TIMEOUT, OFBufferId.NO_BUFFER, remFlag);
280 }
281 }
282
283 /**
284 * Processes a OFPacketIn message. If the switch has learned the MAC to port mapping
285 * for the pair it will write a FlowMod for. If the mapping has not been learned the
286 * we will flood the packet.
287 * @param sw
288 * @param pi
289 * @param cntx
290 * @return
291 */
292 @SuppressWarnings("unused")
293 private Command processPacketInMessage(IOFSwitch sw, OFPacketIn pi, FloodlightContext cntx)
294 {
295 Integer lnk_count;
296
297 // Read inPort and declare outPort
298 OFPort inPort = (pi.getVersion().compareTo(OFVersion.OF_12) < 0 ? pi.getInPort() : pi.getMatch().get(MatchField.IN_PORT));
299 OFPort outPort;
300
301 /* Read packet header attributes into a Match object */
302 Match match = createMatchFromPacket(sw, inPort, cntx);
303 MacAddress sourceMac = match.get(MatchField.ETH_SRC);
304 MacAddress destMac = match.get(MatchField.ETH_DST);
305
306 if (sourceMac == null)
307 {
308 sourceMac = MacAddress.NONE;
309 }
310 if (destMac == null)
311 {
312 destMac = MacAddress.NONE;
313 }
314
315 if ((destMac.getLong() & 0xfffffffffff0L) == 0x0180c2000000L)
316 {
317 if (log.isTraceEnabled())
318 {
319 log.info("ignoring packet addressed to 802.1D/Q reserved addr: switch {} dest MAC {}",
320 new Object[]{ sw,
321 destMac.toString() });
322 }
323 return Command.STOP;
324 }
325
326 if ( (sourceMac.getLong() & 0x010000000000L) == 0)
327 {
328 // If source MAC is a unicast address, learn the port for this MAC/VLAN
329 addToPortMap(sw, sourceMac, inPort); // If the entry already exists, it is replaced
330 }
331
332 // Check if port for destination MAC is known
333 // If so output flow-mod and/or packet
334 // If link destination number is exceeded, drop
335 if ( (outPort = getFromPortMap(sw, destMac)) == null)
336 {
337 // No port entry for the given MAC - Flood the packet
338 SwitchCommands.sendPacketOutPacketIn(sw, OFPort.FLOOD, pi);
339 log.info( "Sw: " + sw
340 + " ... Flooding: "
341 + "SRC {} DEST {}",
342 new Object[]{ sourceMac.toString(),
343 destMac.toString()});
344 } // End of Flood
345 else
346 {
347 // If there is no MacLinkCounter entry for the SourceMAC
348 // Push packet to switch
349 SwitchCommands.sendPacketOutPacketIn(sw, outPort, pi);
350 log.info( "Sw: " + sw
351 + " ... Sending packet to known destination port: "
352 + "SRC {} DEST {} inP {} outP {} {}",
353 new Object[]{ sourceMac.toString(),
354 destMac.toString(),
355 inPort.getPortNumber(),
356 outPort.getPortNumber() });
357
358 // Extract Ethernet Packet
359 Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD);
360
361 if ( eth.getEtherType() == EthType.IPv4 )
362 {
363 IPv4 ipv4 = (IPv4) eth.getPayload();
364
365 IPv4Address ipv4src = ipv4.getSourceAddress();
366 IPv4Address ipv4dest = ipv4.getDestinationAddress();
367
368 if ( ipv4.getProtocol() == IpProtocol.TCP )
369 {
370 TCP tcp = (TCP) ipv4.getPayload();
371
372 TransportPort portSrc = tcp.getSourcePort();
373 TransportPort portDest = tcp.getDestinationPort();
374
375 Pair<IPv4Address,TransportPort> ipport = new Pair<IPv4Address,TransportPort>(ipv4src, portSrc);
376
377 Match tcpmatch = createMatchFromTCPPacket(sw, outPort, cntx);
378
379 if ( ( lnk_count = TCPLinkCounterMap.get(ipport) ) != null && lnk_count >= MAX_DESTINATION_NUMBER)
380 {
381 // Link Destinations exceeded, drop packet.
382 log.info( "Sw: " + sw
383 + " ---> Excessive Connections: "
384 + "TCP {} IP {} LinkCount {}",
385 new Object[]{ portSrc.toString(),
386 ipv4src.toString(),
387 lnk_count });
388
389 } // End of Max Connections
390 else
391 {
392 // Create or Increment MAC Counter entry
393 if ( (lnk_count = TCPLinkCounterMap.putIfAbsent(ipport, 1)) != null)
394 {
395 TCPLinkCounterMap.replace(ipport, ++lnk_count);
396 } // End of Increment Table
397
398 log.info( "Sw: " + sw
399 + " *** Link Count Update: "
400 + "TCP {} IP {} LinkCount {}",
401 new Object[]{ portSrc.toString(),
402 ipv4src.toString(),
403 TCPLinkCounterMap.get(new Pair<IPv4Address, TransportPort>(ipv4src, portSrc)) });
404
405 // Create TCP/PORT Flow
406 createFlowMod(sw, outPort, tcpmatch, pi.getVersion(), CGRmodule.FLOWMOD_PRIORITY, true);
407
408
409 log.info( "Sw: " + sw
410 + " *** New TCP Flow: "
411 + "IP_SRC {}:{} IP_DEST {}:{} PORT {}",
412 new Object[]{ ipv4src.toString(),
413 portSrc.toString(),
414 ipv4dest.toString(),
415 portDest.toString(),
416 outPort.getPortNumber() });
417
418 } // End of Create New Flow - Maximum Connections not reached
419 } // End of TCP Packet
420 } // End of IPv4 Packet
421
422 if (sourceMac != null && destMac != null)
423 {
424 // Add flow table entry matching source MAC, dest MAC and input port
425 // that sends to the port we previously learned for the dest MAC.
426 // We write FlowMods with Buffer ID none then explicitly PacketOut the buffered packet
427 createFlowMod(sw, outPort, match, pi.getVersion(), CGRmodule.DEFAULT_PRIORITY, false);
428
429 // Also add a flow table entry with source and destination MACs reversed, and
430 // input and output ports reversed.
431 if (LEARNING_SWITCH_REVERSE_FLOW && false)
432 {
433 // Create Reserve Match
434 Match rev_match = createReverseMatchfromMatch(sw, inPort, match); // CHECK PORT TO USE /IN/OUT
435 createFlowMod(sw, inPort, rev_match, pi.getVersion(), CGRmodule.DEFAULT_PRIORITY, false);
436 }
437
438 } // End of srcMac & srcDest != NULL
439 } // End of Know Destination Port
440 return Command.STOP;
441 }
442
443 /**
444 * Processes a flow removed message.
445 * @param sw The switch that sent the flow removed message.
446 * @param flowRemovedMessage The flow removed message.
447 * @return Whether to continue processing this message or stop.
448 */
449 @SuppressWarnings("unused")
450 private Command processFlowRemovedMessage(IOFSwitch sw, OFFlowRemoved flowRemovedMessage) {
451 Integer lnk_count;
452 Match match = flowRemovedMessage.getMatch();
453 MacAddress srcMac = match.get(MatchField.ETH_SRC);
454 MacAddress dstMac = match.get(MatchField.ETH_DST);
455
456 IPv4Address srcIPv4 = match.get(MatchField.IPV4_SRC);
457 IPv4Address dstIPv4 = match.get(MatchField.IPV4_DST);
458
459 TransportPort srcPort = match.get(MatchField.TCP_SRC);
460 TransportPort dstPort = match.get(MatchField.TCP_DST);
461
462 if (srcIPv4 != null
463 && dstIPv4 != null
464 && srcPort != null
465 && dstPort != null)
466 {
467 Pair<IPv4Address,TransportPort> ipport = new Pair<IPv4Address,TransportPort>(srcIPv4, srcPort);
468
469 // Decrement MAC counter links
470 if ( (lnk_count = TCPLinkCounterMap.get(ipport) ) != null /*&& lnk_count > 0*/)
471 {
472 TCPLinkCounterMap.replace(ipport, --lnk_count);
473 }
474
475 log.info( "Sw: " + sw
476 + " *** TCP Flow Removed: "
477 + "SRC {} LinkCount {}",
478 new Object[]{ ipport.toString(),
479 TCPLinkCounterMap.get(ipport) });
480 } // End of TCP Match
481
482
483
484
485 // When a flow entry expires, it means the device with the matching source
486 // MAC address either stopped sending packets or moved to a different
487 // port. If the device moved, we can't know where it went until it sends
488 // another packet, allowing us to re-learn its port. Meanwhile we remove
489 // it from the macToPortMap to revert to flooding packets to this device.
490 removeFromPortMap(sw, srcMac);
491
492 // Also, if packets keep coming from another device (e.g. from ping), the
493 // corresponding reverse flow entry will never expire on its own and will
494 // send the packets to the wrong port (the matching input port of the
495 // expired flow entry), so we must delete the reverse entry explicitly.
496 if(LEARNING_SWITCH_REVERSE_FLOW && false) {
497 Match rev_match = createReverseMatchfromMatch(sw, match);
498 SwitchCommands.removeRules(sw, rev_match, flowRemovedMessage.getVersion() );
499 }
500
501 return Command.CONTINUE;
502 }
503
504 // IOFMessageListener
505
506 @Override
507 public Command receive(IOFSwitch sw, OFMessage msg, FloodlightContext cntx) {
508 switch (msg.getType()) {
509 case PACKET_IN:
510 return this.processPacketInMessage(sw, (OFPacketIn) msg, cntx);
511 case FLOW_REMOVED:
512 return this.processFlowRemovedMessage(sw, (OFFlowRemoved) msg);
513 case ERROR:
514 log.info("received an error {} from switch {}", msg, sw);
515 return Command.CONTINUE;
516 default:
517 log.error("received an unexpected message {} from switch {}", msg, sw);
518 return Command.CONTINUE;
519 }
520 }
521
522 @Override
523 public boolean isCallbackOrderingPrereq(OFType type, String name) {
524 return false;
525 }
526
527 @Override
528 public boolean isCallbackOrderingPostreq(OFType type, String name) {
529 return (type.equals(OFType.PACKET_IN) && name.equals("forwarding")) ;
530 }
531
532 // IFloodlightModule
533
534 /**
535 * Tell the module system which services we provide.
536 */
537 @Override
538 public Collection<Class<? extends IFloodlightService>> getModuleServices()
539 { return null; }
540
541 /**
542 * Tell the module system which services we implement.
543 */
544 @Override
545 public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls()
546 { return null; }
547
548 @Override
549 public Collection<Class<? extends IFloodlightService>> getModuleDependencies() {
550 Collection<Class<? extends IFloodlightService>> l =
551 new ArrayList<Class<? extends IFloodlightService>>();
552 l.add(IFloodlightProviderService.class);
553 return l;
554 }
555
556 @Override
557 public void init(FloodlightModuleContext context) throws FloodlightModuleException {
558 ControllerMap = new ConcurrentHashMap<IOFSwitch, Map<MacAddress, OFPort>>();
559 TCPLinkCounterMap = new ConcurrentHashMap< Pair<IPv4Address,TransportPort>, Integer>();
560 floodlightProviderService = context.getServiceImpl(IFloodlightProviderService.class);
561 log.info("CGR module started {}");
562 }
563
564 @Override
565 public void startUp(FloodlightModuleContext context)
566 {
567 // paag: register the IControllerCompletionListener
568 floodlightProviderService.addOFMessageListener(OFType.PACKET_IN, this);
569 floodlightProviderService.addOFMessageListener(OFType.FLOW_REMOVED, this);
570 floodlightProviderService.addOFMessageListener(OFType.ERROR, this);
571
572 // read our config options
573 Map<String, String> configOptions = context.getConfigParams(this);
574 try {
575 String idleTimeout = configOptions.get("idletimeout");
576 if (idleTimeout != null) {
577 FLOWMOD_DEFAULT_IDLE_TIMEOUT = Short.parseShort(idleTimeout);
578 }
579 } catch (NumberFormatException e) {
580 log.warn("Error parsing flow idle timeout, " +
581 "using default of {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT);
582 }
583 try {
584 String hardTimeout = configOptions.get("hardtimeout");
585 if (hardTimeout != null) {
586 FLOWMOD_DEFAULT_HARD_TIMEOUT = Short.parseShort(hardTimeout);
587 }
588 } catch (NumberFormatException e) {
589 log.warn("Error parsing flow hard timeout, " +
590 "using default of {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT);
591 }
592 try {
593 String priority = configOptions.get("priority");
594 if (priority != null) {
595 FLOWMOD_PRIORITY = Short.parseShort(priority);
596 }
597 } catch (NumberFormatException e) {
598 log.warn("Error parsing flow priority, " +
599 "using default of {}",
600 FLOWMOD_PRIORITY);
601 }
602 log.debug("FlowMod idle timeout set to {} seconds", FLOWMOD_DEFAULT_IDLE_TIMEOUT);
603 log.debug("FlowMod hard timeout set to {} seconds", FLOWMOD_DEFAULT_HARD_TIMEOUT);
604 log.debug("FlowMod priority set to {}", FLOWMOD_PRIORITY);
605 }
606
607}