def all_timeout(self, current_time): """ Also timeout flows in secondary table """ # timeout primary table #expired = [k for k, v in self.table.items() if v.active and self.check_timeout(v, current_time)] should_expired = [] while len(self.should_active) > 0: earliest = self.should_active[0] if self.check_delta(current_time, earliest[1], self.timeout): should_expired.append(self.should_active.pop(0)[0]) else: break should_active_ids = [i[0] for i in self.should_active] for id in should_expired: flow = self.table[id] if not flow.active or id in should_active_ids: continue self.deactivate_flow(id) # Rule #1, fixed timeout if self.timeout_policy == 1: # a miss happens for a second time, insert into cache when timed out # in reality, controller will tell switch this information if self.table[id].num_rules() >= self.threshold: Output.DEBUG("Adding to secondary") self.secondary_table[id] = current_time + ( self.timeout * self.cache_multiplier) / 1000 # in seconds # Rule #2, timeout based on last rules elif self.timeout_policy == 2: # the threshold must be greater than 2, because of course # TODO: make it variable flow = self.table[id] if flow.num_rules() >= self.threshold: last_rule = flow.rules[-1] second_last = flow.rules[-2] cachetime = current_time + (last_rule.first_seen - second_last.last_update) * 1.1 if (last_rule.first_seen - second_last.last_update) > 1: cachetime = current_time + 1 # greater than 1 second make it 1 second self.secondary_table[id] = cachetime # timeout secondary table expired = [ k for k, v in self.secondary_table.items() if current_time > v ] for k in expired: Output.DEBUG("deleting " + k + " from secondary") del self.secondary_table[k]
def existing_flow(self, packet): id = packet.get_id() if not self.if_flow_exists(id): raise Exception("Flow does not exist") flow = self.table[id] latest_rule = None if flow.active: latest_rule = flow.rules[-1] elif self.if_secondary_exists(id) and not flow.active: self.table[id].active = True self.secondary_table.remove(id) self.current_active_flow += 1 latest_rule = flow.rules[-1] else: latest_rule = flow.create_rule(packet.timestamp) self.missed += 1 self.total_rules += 1 self.current_active_flow += 1 flow.active = True Output.DEBUG("Added new rule") flow.last_update = packet.timestamp latest_rule.new_packet(packet) self.table[id] = flow if self.current_active_flow > self.max_flow_count: self.max_flow_count = self.current_active_flow
def existing_flow(self, packet): id = packet.get_id() if not self.if_flow_exists(id): raise Exception("Flow does not exist") flow = self.table[id] latest_rule = None cur_time = packet.timestamp if flow.active: latest_rule = flow.rules[-1] elif self.if_secondary_exists(id) and not flow.active: # in secondary table self.table[id].active = True del self.secondary_table[id] # remove entry in cache self.current_active_flow += 1 latest_rule = flow.rules[-1] else: latest_rule = flow.create_rule(cur_time) self.missed += 1 self.total_rules += 1 self.current_active_flow += 1 flow.active = True Output.DEBUG("Added new rule") flow.last_update = cur_time latest_rule.new_packet(packet) self.table[id] = flow if self.current_active_flow > self.max_flow_count: self.max_flow_count = self.current_active_flow self.should_active.append((flow.id, flow.last_update))
def existing_flow(self, packet): ''' Handles cases where a flow already exists. If it's active, update the last rule in rule list. If it's not active, a new rule needs to be created. ''' id = packet.get_id() if not self.if_flow_exists(id): raise Exception("Flow does not exist") flow = self.table[id] latest_rule = None if flow.active: latest_rule = flow.rules[-1] else: latest_rule = flow.create_rule(packet.timestamp) self.missed += 1 self.total_rules += 1 self.current_active_flow += 1 flow.active = True Output.DEBUG("Added new rule") flow.last_update = packet.timestamp latest_rule.new_packet(packet) self.table[id] = flow if self.current_active_flow > self.max_flow_count: self.max_flow_count = self.current_active_flow self.should_active.append((flow.id, flow.last_update))
def check_timeout(self, flow, current_time): # converts to ms delta = (current_time - flow.last_update) * 1000 if self.check_delta(current_time, flow.last_update, self.timeout): Output.DEBUG("Timing out " + flow.id) return True else: return False
def check_timeout(self, flow, current_time): # converts to ms timeout = self.timeout_table[flow.id][-1] if self.check_delta(current_time, flow.last_update, timeout): Output.DEBUG("Timing out " + flow.id) return True else: return False
def push_secondary(self, id): if len(self.secondary_table) > self.secondary_table_size: Output.DEBUG("Evicting: " + id) self.eviction_policy() self.secondary_table.append(id)
def process_packet(self, timestamp, raw_packet): ''' Process an IP packet and output statstics ''' Output.VERBOSE("---------Processing Packet At Time:----------") Output.VERBOSE(datetime.utcfromtimestamp(timestamp)) self.current_time = timestamp self.total_packets += 1 if (self.current_time - self.last_dump_time) * 1000 > self.dump_interval: self.flow_table.all_timeout(self.current_time) self.output_statistics(self.to_file) self.last_dump_time = self.current_time try: eth = dpkt.ethernet.Ethernet(raw_packet) except Exception: return ip = eth.data if not isinstance(ip, dpkt.ip.IP): Output.VERBOSE("Not an IP packet") return packet = Packet(timestamp) packet.size = len(raw_packet) packet.eth_src = eth.src packet.eth_dst = eth.dst packet.eth_type = eth.type packet.ip_src = ip.src packet.ip_dst = ip.dst packet.ip_protocol = ip.p tcp, udp = None, None if packet.ip_protocol == IP_PROTOCOL.TCP: # tcp tcp = ip.data elif packet.ip_protocol == IP_PROTOCOL.UDP: # udp udp = ip.data else: Output.VERBOSE("Not TCP or UDP") return if tcp and type(tcp) == dpkt.tcp.TCP: packet.sport = tcp.sport packet.dport = tcp.dport elif udp and type(udp) == dpkt.udp.UDP: packet.sport = udp.sport packet.dport = udp.dport else: return id = packet.get_id() if self.flow_table.if_flow_exists(id): self.flow_table.existing_flow(packet) else: self.flow_table.non_existing_flow(packet)