def state_s1(self, dvalues): # Calculate test output of left node of current pointer # If test output = 1: # Move the pointer to the left child of (l,k) # State = 0 # Else if test output = 0: # State = 2 # Update x_mean and s # In state one: the checking node is the left node of current pointer # Read aggregated value of the current checking node node = self.checking_node val = self._read(node, dvalues, self.alpha, self.beta) output = self._test_func(node, self.alpha, self.beta, self.eta) self._debug_print('state_s1', node, val, self.alpha, self.beta, output) if output == -1: # Continue taking samples return elif output == 1: # Move the pointer to the left child of (l,k) left_child_l, left_child_k = get_left_child( self.curr_node.l, self.curr_node.k, self.depth) self.curr_node = self._createNode(left_child_l, left_child_k, node) self.alpha, self.beta = self.p0, self.p0 self.state = 0 elif output == 0: self.state = 2 right_child_l, right_child_k = get_right_child( self.curr_node.l, self.curr_node.k, self.depth) self.checking_node = self._createNode(right_child_l, right_child_k) else: self.logger.error("Invalid test output = %d", output)
def state_s2(self, dvalues, HHH_nodes): # Calculate test output of right node of current pointer # If test output = 1: # Move the pointer to the right child of (l,k) # State = 0 # Else if test output = 0: # If alpha < threshold: # Declare (l,k) as the target # Else: # Divide alpha and beta by 2 # Update x_mean and s # In state two: the checking node is the right node of current pointer # Read aggregated value of the current checking node node = self.checking_node val = self._read(node, dvalues, HHH_nodes, self.alpha, self.beta) output = self._test_func(node, self.alpha, self.beta, self.eta) self._debug_print('state_s2', node, val, self.alpha, self.beta, output) if output == -1: # Continue taking samples return elif output == 1: # Move the pointer to the right child of (l,k) right_child_l, right_child_k = get_right_child( self.curr_node.l, self.curr_node.k, self.depth) #self.curr_node = self._createNode(right_child_l, right_child_k, node) self.curr_node = self._copyNode(node) self.alpha, self.beta = self.p0, self.p0 self.state = 0 elif output == 0: if self.alpha < self.leaf_alpha: # Declare current node (l,k) as the target self._report() ret = self._copyNode(self.curr_node) # Reset pointer to the root node self.curr_node = self._createNode(0, 0) self.alpha, self.beta = self.p0, self.p0 self.state = 0 return ret else: self.alpha, self.beta = self.alpha / 2.0, self.beta / 2.0 self.state = 0 # Keep the old record or not? # Comparison shows that keeping record has better performance #self.curr_node = self._createNode(self.curr_node.l, self.curr_node.k) else: self.logger.error("Pntr %d: Invalid test output = %d", self.pid, output)
def find_start_nodes(self): # Find start nodes to monitor S = self.S l0 = int(math.log(S, 2)) l0_num = 2**(l0+1) - S l1_num = 2*S - 2**(l0+1) curr_monitors = [] for i in range(l0_num): node = (l0, i) curr_monitors.append(node) for i in range(l0_num, 2**l0): node = (l0+1, i*2) curr_monitors.append(node) node = (l0+1, i*2+1) curr_monitors.append(node) curr_monitors = set(curr_monitors) curr_monitors.add((0,0)) self.prefixes = list(curr_monitors) self.logger.debug("At t=%d, monitoring prefixes: %s", self.time_interval+1, \ ','.join(str(k) for k in sorted(self.prefixes, key = lambda x:x[0], reverse=True))) # Find start nodes to measure children = set() for node in curr_monitors: node_l, node_k = node if node_l == self.leaf_level: # Leaf node children.add(node) else: # Non-leaf node children.add(get_left_child(node_l, node_k, self.leaf_level)) children.add(get_right_child(node_l, node_k, self.leaf_level)) # Always monitor the root node = (1,0) children.add(node) node = (1,1) children.add(node) self.children = list(children) self.children = sorted(self.children, key = lambda x:x[0], reverse=True) self.logger.debug("Initial install rules at nodes: %s", ','.join(str(k) for k in children))
def run(self, dvalues): """Function called at each time interval to find reported/measured HHHes. """ self.time_interval += 1 #self.logger.debug("At t=%d, leaf node values: %s", self.time_interval, \ # ','.join(str(k)+':'+str(v)+' ' for k,v in sorted(dvalues.items(), key = lambda x:x[0][1]))) # Read aggregated counters from installed rules. curr_vals = {} for (l,k) in self.children: curr_vals[(l,k)] = read(l, k, dvalues) self.logger.debug("At t=%d, threshold = %f, aggregated values of rules: %s", self.time_interval, self.threshold, \ ','.join(str(k)+':'+str(v)+' ' for k,v in sorted(curr_vals.items(), key = lambda x:x[0][0], reverse=True))) # Process the counts as TCAM entries, the same packet won't count twice. sorted_nodes = sorted(curr_vals.keys(), key = lambda x:x[0], reverse=True) for node in sorted_nodes: val = curr_vals[node] l, k = node pl, pk = l-1, k/2 while pl >= 0: if (pl, pk) in curr_vals: curr_vals[(pl, pk)] -= val pl, pk = pl-1, pk/2 self.logger.debug("At t=%d, threshold = %f, values of rules: %s", self.time_interval, self.threshold, \ ','.join(str(k)+':'+str(v)+' ' for k,v in sorted(curr_vals.items(), key = lambda x:x[0][0], reverse=True))) # Find reported HHHes mHHH = [] mHHH_tags = set() # If node count of node p is below the threshold, we add p's count to the # nearest upstream prefix in the TCAM. for (l,k) in sorted(self.prefixes, key = lambda x:x[0], reverse=True): val = 0 if l == self.leaf_level: # If leaf node val = curr_vals[(l,k)] if val > self.threshold and not (l,k) in mHHH_tags: newNode = Node(l, k, val) mHHH.append(newNode) mHHH_tags.add((l,k)) curr_vals[(l,k)] = 0 else: pl, pk = l-1, k/2 while pl>=0: if (pl, pk) in self.children: curr_vals[(pl, pk)] += val break pl, pk = pl-1, pk/2 else: # It is possible that the number of reported HHHes are larger than Smax # therefore some reported HHHes don't have enought counters to monitor # their children. # If non-leaf node left_child = get_left_child(l, k, self.leaf_level) if not left_child in curr_vals: continue left_val = curr_vals[left_child] if left_child else 0 if left_val > self.threshold: if not left_child in mHHH_tags: newNode = Node(left_child[0], left_child[1], left_val) mHHH.append(newNode) mHHH_tags.add(left_child) else: val += left_val right_child = get_right_child(l, k, self.leaf_level) if not right_child in curr_vals: continue right_val = curr_vals[right_child] if right_child else 0 if right_val > self.threshold: if not right_child in mHHH_tags: newNode = Node(right_child[0], right_child[1], right_val) mHHH.append(newNode) mHHH_tags.add(right_child) else: val += right_val if val > self.threshold: if not (l,k) in mHHH_tags: newNode = Node(l, k, val) mHHH.append(newNode) mHHH_tags.add((l,k)) curr_vals[(l,k)] = 0 else: curr_vals[(l,k)] = val pl, pk = l-1, k/2 if not (pl,pk) in self.prefixes: while pl >=0: if (pl, pk) in self.children: curr_vals[(pl, pk)] += val break pl, pk = pl-1, pk/2 self.logger.info('Reported HHHes: %s', ', '.join(str((node.l, node.k))+': '+str(node.val) for node in sorted(mHHH, key=lambda x:x.l, reverse=True))) # Prepare rules for next time interval self.prefixes = set([(node.l, node.k) for node in mHHH]) self.prefixes.add((0,0)) children = set() # Always monitor the root node = (1,0) children.add(node) node = (1,1) children.add(node) # Monitor children of reported HHHes for node in sorted(mHHH, key=lambda x:x.val, reverse=True): l, k = node.l, node.k if l == self.leaf_level: # Leaf node children.add((l,k)) if len(children) == self.num_of_TCAM: break else: children.add(get_left_child(l, k, self.leaf_level)) if len(children) == self.num_of_TCAM: break children.add(get_right_child(l, k, self.leaf_level)) if len(children) == self.num_of_TCAM: break # If there are spare entries if len(children) < self.num_of_TCAM: # Sort existing HHHes in increasing order sorted_hhh_nodes = sorted(mHHH, key = lambda x:x.val) # Use spare rules to monitor the parents of existing HHHes # We install rules to monitor these HHHes' siblings. for node in sorted_hhh_nodes: sibling_node = get_sibling(node.l, node.k) if sibling_node: children.add(sibling_node) self.prefixes.add(get_parent(node.l, node.k)) if len(children) == self.num_of_TCAM: break self.children = list(children) self.prefixes = list(self.prefixes) self.logger.debug("At t=%d, monitoring prefixes: %s", self.time_interval+1, \ ','.join(str(k) for k in sorted(self.prefixes, key = lambda x:x[0], reverse=True))) self.logger.debug("At t=%d, TCAM num: %d, used num: %d, installing rules at nodes: %s", \ self.time_interval+1, self.num_of_TCAM, len(self.children), \ ','.join(str(k) for k in sorted(self.children, key = lambda x:x[0], reverse=True))) return mHHH