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