def __add_action_to_rule(self, action, rule, rtr): #print "Action:", action, " Rule: ",rule mask = wildcard_create_bit_repeat(self.format["length"], 2) rewrite = wildcard_create_bit_repeat(self.format["length"], 1) out_ports = [] rw = False push = False pop = False for operation in action.keys(): if operation == "set_nw_src" or operation == "set_nw_dst": rw = True set_header_field(self.format, mask, operation[4:], 0, 0) set_header_field(self.format, rewrite, operation[4:], dotted_ip_to_int(action[operation]), 0) elif operation == "set_dl_src" or operation == "set_dl_dst": rw = True set_header_field(self.format, mask, operation[4:], 0, 0) set_header_field(self.format, rewrite, operation[4:], mac_to_int(action[operation]), 0) elif operation == "output": ''' if action[operation] in self.port_members: out_ports = self.__encode_port_list(self.port_members[action[operation]],rtr) else: ''' if action[operation].startswith("mport"): out_ports = self.__expand_mport(rtr, action[operation]) else: out_ports = [action[operation]] out_ports = self.__compress_port_list(out_ports) out_ports = self.__encode_port_list(out_ports, rtr) elif operation == "push_ip": push = True rule["encap_pos"] = self.format["nw_src_pos"] rule["encap_len"] = 8 elif operation == "pop_ip": pop = True rule["decap_pos"] = self.format["nw_src_pos"] rule["decap_len"] = 8 rule["out_ports"] = out_ports if push: rule["action"] = "encap" rule["mask"] = mask rule["rewrite"] = rewrite elif pop: rule["action"] = "decap" rule["mask"] = None rule["rewrite"] = None elif rw: rule["action"] = "rw" rule["mask"] = mask rule["rewrite"] = rewrite else: rule["action"] = "fwd" rule["mask"] = None rule["rewrite"] = None
def parse_rule(self, rule): ''' Parses a single rule and generate openflow entry for that rule. the resulting openflow entry will have this format: FIEDL_wc: if the field is not wildcarded (0) or wildcarded (1) for IP fields, this a number between 0-32 counting number of wildcarded bits from right FIELD_match: the match value for this field, after applying appropriate wildcard. FIELD_new: in case of a rewrite action, the new field value to be rewritten. ''' fields = [ "mac_src", "mac_dst", "vlan", "ip_src", "ip_dst", "ip_proto", "transport_src", "transport_dst" ] openflow_entry = {} for field in fields: if "%s_pos" % field not in self.hs_format.keys(): continue position = self.hs_format["%s_pos" % field] l = self.hs_format["%s_len" % field] wildcarded = True field_match = wildcard_create_bit_repeat(l, 0x1) field_mask = wildcard_create_bit_repeat(l, 0x1) field_rewrite = wildcard_create_bit_repeat(l, 0x1) for i in range(l): field_match[i] = rule["match"][position + i] if rule["mask"] != None: field_mask[i] = rule["mask"][position + i] field_rewrite[i] = rule["rewrite"][position + i] if field_match[i] != 0xffff: wildcarded = False if wildcarded: if field == "ip_src" or field == "ip_dst": openflow_entry["%s_wc" % field] = 32 else: openflow_entry["%s_wc" % field] = 1 openflow_entry["%s_match" % field] = 0 else: if field == "ip_src" or field == "ip_dst": parsed = self.parse_non_wc_field(field_match, True) else: parsed = self.parse_non_wc_field(field_match, False) openflow_entry["%s_wc" % field] = parsed[1] openflow_entry["%s_match" % field] = parsed[0] if (rule["mask"] != None): openflow_entry["%s_new"%field] = self.find_new_field(\ field_match,field_mask,field_rewrite) else: openflow_entry["%s_new" % field] = None openflow_entry["in_ports"] = rule["in_ports"] openflow_entry["out_ports"] = rule["out_ports"] return openflow_entry
def __add_action_to_rule(self,action,rule,rtr): #print "Action:", action, " Rule: ",rule mask = wildcard_create_bit_repeat(self.format["length"],2) rewrite = wildcard_create_bit_repeat(self.format["length"],1) out_ports = [] rw = False push = False pop = False for operation in action.keys(): if operation == "set_nw_src" or operation == "set_nw_dst": rw = True set_header_field(self.format, mask, operation[4:], 0, 0) set_header_field(self.format, rewrite, operation[4:], dotted_ip_to_int(action[operation]), 0) elif operation == "set_dl_src" or operation == "set_dl_dst": rw = True set_header_field(self.format, mask, operation[4:], 0, 0) set_header_field(self.format, rewrite, operation[4:], mac_to_int(action[operation]), 0) elif operation == "output": ''' if action[operation] in self.port_members: out_ports = self.__encode_port_list(self.port_members[action[operation]],rtr) else: ''' if action[operation].startswith("mport"): out_ports = self.__expand_mport(rtr, action[operation]) else: out_ports = [action[operation]] out_ports = self.__compress_port_list(out_ports) out_ports = self.__encode_port_list(out_ports, rtr) elif operation == "push_ip": push = True rule["encap_pos"] = self.format["nw_src_pos"] rule["encap_len"] = 8 elif operation == "pop_ip": pop = True rule["decap_pos"] = self.format["nw_src_pos"] rule["decap_len"] = 8 rule["out_ports"] = out_ports if push: rule["action"] = "encap" rule["mask"] = mask rule["rewrite"] = rewrite elif pop: rule["action"] = "decap" rule["mask"] = None rule["rewrite"] = None elif rw: rule["action"] = "rw" rule["mask"] = mask rule["rewrite"] = rewrite else: rule["action"] = "fwd" rule["mask"] = None rule["rewrite"] = None
def __init__(self, name, hs, ports, length): ''' @name: a unique name for this source node ''' Node.__init__(self) self.node_id = name self.output_ports = ports self.input_ports = [] hs.push_applied_tf_rule(None, self.node_id, None) self.source_flow.append((hs, None)) self.match = wildcard_create_bit_repeat(length, 0x3) self.inverse_match = wildcard_create_bit_repeat(length, 0x3)
def parse_rule(self,rule): ''' Parses a single rule and generate openflow entry for that rule. the resulting openflow entry will have this format: FIEDL_wc: if the field is not wildcarded (0) or wildcarded (1) for IP fields, this a number between 0-32 counting number of wildcarded bits from right FIELD_match: the match value for this field, after applying appropriate wildcard. FIELD_new: in case of a rewrite action, the new field value to be rewritten. ''' fields = ["mac_src", "mac_dst", "vlan", "ip_src", "ip_dst", "ip_proto", "transport_src", "transport_dst"] openflow_entry = {} for field in fields: if "%s_pos"%field not in self.hs_format.keys(): continue position = self.hs_format["%s_pos"%field] l = self.hs_format["%s_len"%field] wildcarded = True field_match = wildcard_create_bit_repeat(l,0x1) field_mask = wildcard_create_bit_repeat(l,0x1) field_rewrite = wildcard_create_bit_repeat(l,0x1) for i in range(l): field_match[i] = rule["match"][position+i] if rule["mask"] != None: field_mask[i] = rule["mask"][position+i] field_rewrite[i] = rule["rewrite"][position+i] if field_match[i] != 0xffff: wildcarded = False if wildcarded: if field == "ip_src" or field == "ip_dst": openflow_entry["%s_wc"%field] = 32 else: openflow_entry["%s_wc"%field] = 1 openflow_entry["%s_match"%field] = 0 else: if field == "ip_src" or field == "ip_dst": parsed = self.parse_non_wc_field(field_match, True) else: parsed = self.parse_non_wc_field(field_match, False) openflow_entry["%s_wc"%field] = parsed[1] openflow_entry["%s_match"%field] = parsed[0] if (rule["mask"] != None): openflow_entry["%s_new"%field] = self.find_new_field(\ field_match,field_mask,field_rewrite) else: openflow_entry["%s_new"%field] = None openflow_entry["in_ports"] = rule["in_ports"] openflow_entry["out_ports"] = rule["out_ports"] return openflow_entry
def __init__(self,name,hs,ports,length): ''' @name: a unique name for this source node ''' Node.__init__(self) self.node_id = name self.output_ports = ports self.input_ports = [] hs.push_applied_tf_rule(None, self.node_id, None) self.source_flow.append((hs,None)) self.match = wildcard_create_bit_repeat(length,0x3) self.inverse_match = wildcard_create_bit_repeat(length,0x3)
def acl_dict_entry_to_wc(self,dic_entry): result = [] result.append(wildcard_create_bit_repeat(self.hs_format["length"],0x3)) if (dic_entry["ip_protocol"] != 0): self.set_field(result[0], "ip_proto", dic_entry["ip_protocol"], 0) self.set_field(result[0], "ip_src", dic_entry["src_ip"], find_num_mask_bits_right_mak(dic_entry["src_ip_mask"])) self.set_field(result[0], "ip_dst", dic_entry["dst_ip"], find_num_mask_bits_right_mak(dic_entry["dst_ip_mask"])) tp_src_matches = range_to_wildcard(dic_entry["transport_src_begin"],dic_entry["transport_src_end"],16) tmp = [] for tp_src_match in tp_src_matches: w = wildcard_copy(result[0]) self.set_field(w, "tcp_src", tp_src_match[0], tp_src_match[1]) tmp.append(w) result = tmp tp_dst_matches = range_to_wildcard(dic_entry["transport_dst_begin"],dic_entry["transport_dst_end"],16) tmp = [] for tp_dst_match in tp_dst_matches: for r in result: w = wildcard_copy(r) self.set_field(w, "tcp_dst", tp_dst_match[0], tp_dst_match[1]) tmp.append(w) result = tmp tp_ctrl_matches = range_to_wildcard(dic_entry["tcp_ctrl_begin"],dic_entry["tcp_ctrl_end"],8) tmp = [] for tp_ctrl_matche in tp_ctrl_matches: for r in result: w = wildcard_copy(r) self.set_field(w, "tcp_ctrl", tp_ctrl_matche[0], tp_ctrl_matche[1]) tmp.append(w) result = tmp return result
def find_entries(self,wildcard_search,port): m = wildcard_create_bit_repeat(len(self.match_indices),1) for i in range(len(self.match_indices)): m[i] = wildcard_search[self.match_indices[i]] match_key_string = "%s"%m index = match_key_string.find('x') if index != -1: match_key_string = match_key_string[:index] elif index == 0: return None rule_set = [] try: if len(match_key_string) == len(self.exact_match_indices) * 8: #full match rule_set = self.inport_to_table["%d"%port][match_key_string] \ + self.inport_to_table["%d"%port]["default"] else: #partial match for key in self.exact_match_hash["%d"%port].keys(): if key.startswith(match_key_string): rule_set += self.inport_to_table["%d"%port][key] rule_set += self.inport_to_table["%d"%port]["default"] except: rule_set = self.exact_match_hash["%d"%port]["default"] return rule_set
def __parse_flow_match(self,flow_match): parts = flow_match.split(" ") match = wildcard_create_bit_repeat(self.format["length"],3) num_fields = 0 for part in parts: if not part.startswith("priority") and part != "": fv = part.split("=") field = fv[0] value = fv[1] if field == "dl_src" or field=="dl_dst": ''' m = mac_to_int(value) if m != 0: set_header_field(self.format, match, field, m, 0) ''' pass elif field == "nw_src" or field == "nw_dst": num_fields += 1 (ip,subnet) = dotted_subnet_to_int(value) set_header_field(self.format, match, field, ip, 32-subnet) elif field == "nw_tos": num_fields += 1 set_header_field(self.format, match, field, int(value), 0) elif field == "dl_type": num_fields += 1 set_header_field(self.format, match, field, l2_proto_to_int(value), 0) if num_fields > 0: return match else: return None
def __generate_mp_tf_rules(self, rtr): result_rules = [] for mp in self.multipath[rtr]: group_rule = {"action":"multipath","rules":[]} rule = {} rule["in_ports"] = [self.get_port_id(rtr, mp)+self.PORT_TYPE_MULTIPLIER] rule["match"] = wildcard_create_bit_repeat(self.format["length"],3) is_fwd_action = True for single_action in self.multipath[rtr][mp]: rule_copy = rule.copy() self.__add_action_to_rule(single_action,rule_copy,rtr) if (rule_copy["action"] != "fwd"): is_fwd_action = False group_rule["rules"].append(rule_copy) if (is_fwd_action): all_out_ports = [] for g_rule in group_rule["rules"]: all_out_ports.extend(g_rule["out_ports"]) s = set(all_out_ports) rule["out_ports"] = self.__compress_port_list(list(s)) rule["action"] = "fwd" rule["mask"] = None rule["rewrite"] = None group_rule["rules"] = [rule] result_rules.append(group_rule) else: result_rules.append(group_rule) return result_rules
def __generate_mp_tf_rules(self, rtr): result_rules = [] for mp in self.multipath[rtr]: group_rule = {"action": "multipath", "rules": []} rule = {} rule["in_ports"] = [ self.get_port_id(rtr, mp) + self.PORT_TYPE_MULTIPLIER ] rule["match"] = wildcard_create_bit_repeat(self.format["length"], 3) is_fwd_action = True for single_action in self.multipath[rtr][mp]: rule_copy = rule.copy() self.__add_action_to_rule(single_action, rule_copy, rtr) if (rule_copy["action"] != "fwd"): is_fwd_action = False group_rule["rules"].append(rule_copy) if (is_fwd_action): all_out_ports = [] for g_rule in group_rule["rules"]: all_out_ports.extend(g_rule["out_ports"]) s = set(all_out_ports) rule["out_ports"] = self.__compress_port_list(list(s)) rule["action"] = "fwd" rule["mask"] = None rule["rewrite"] = None group_rule["rules"] = [rule] result_rules.append(group_rule) else: result_rules.append(group_rule) return result_rules
def __parse_flow_match(self, flow_match): parts = flow_match.split(" ") match = wildcard_create_bit_repeat(self.format["length"], 3) num_fields = 0 for part in parts: if not part.startswith("priority") and part != "": fv = part.split("=") field = fv[0] value = fv[1] if field == "dl_src" or field == "dl_dst": ''' m = mac_to_int(value) if m != 0: set_header_field(self.format, match, field, m, 0) ''' pass elif field == "nw_src" or field == "nw_dst": num_fields += 1 (ip, subnet) = dotted_subnet_to_int(value) set_header_field(self.format, match, field, ip, 32 - subnet) elif field == "nw_tos": num_fields += 1 set_header_field(self.format, match, field, int(value), 0) elif field == "dl_type": num_fields += 1 set_header_field(self.format, match, field, l2_proto_to_int(value), 0) if num_fields > 0: return match else: return None
def find_entries(self, wildcard_search, port): m = wildcard_create_bit_repeat(len(self.match_indices), 1) for i in range(len(self.match_indices)): m[i] = wildcard_search[self.match_indices[i]] match_key_string = "%s" % m index = match_key_string.find('x') if index != -1: match_key_string = match_key_string[:index] elif index == 0: return None rule_set = [] try: if len(match_key_string) == len(self.exact_match_indices) * 8: #full match rule_set = self.inport_to_table["%d"%port][match_key_string] \ + self.inport_to_table["%d"%port]["default"] else: #partial match for key in self.exact_match_hash["%d" % port].keys(): if key.startswith(match_key_string): rule_set += self.inport_to_table["%d" % port][key] rule_set += self.inport_to_table["%d" % port]["default"] except: rule_set = self.exact_match_hash["%d" % port]["default"] return rule_set
def parse_new_rule_tokens(tokens, mapf, rtr): in_ports = [] out_ports = [] match = wildcard_create_bit_repeat(HS_FORMAT["length"], 0x3) mask = None rw = None for token in tokens: parts = token.split("=") field_name = parts[0] if field_name.startswith("new"): if mask == None: mask = wildcard_create_bit_repeat(HS_FORMAT["length"], 0x2) rw = wildcard_create_bit_repeat(HS_FORMAT["length"], 0x1) field_name = field_name[4:] if field_name in ["ip_src", "ip_dst"]: [value, left_mask] = dotted_subnet_to_int(parts[1]) right_mask = 32 - left_mask else: value = int(parts[1]) right_mask = 0 set_header_field(cisco_router.HS_FORMAT(), mask, field_name, 0, right_mask) set_header_field(cisco_router.HS_FORMAT(), rw, field_name, value, right_mask) else: if field_name in ["in_ports", "out_ports"]: ports = parts[1].split(",") ports_int = [] for port in ports: ports_int.append(int(mapf[rtr][port])) if field_name == "in_ports": in_ports = ports_int else: out_ports = ports_int else: if field_name in ["ip_src", "ip_dst"]: [value, left_mask] = dotted_subnet_to_int(parts[1]) right_mask = 32 - left_mask else: value = int(parts[1]) right_mask = 0 set_header_field(cisco_router.HS_FORMAT(), match, field_name, value, right_mask) rule = TF.create_standard_rule(in_ports, match, out_ports, mask, rw, "", []) return rule
def wc_header_to_parsed_string(hs_format, fields, i_wc): out_string = "" for field in fields: offset = hs_format["%s_pos" % field] len = hs_format["%s_len" % field] w = wildcard_create_bit_repeat(len, 0x1) for i in range(0, len): w[i] = i_wc[offset + i] out_string = "%s%s:%s, " % (out_string, field, w) return out_string
def wc_header_to_parsed_string(hs_format, fields, i_wc): out_string = "" for field in fields: offset = hs_format["%s_pos"%field] len = hs_format["%s_len"%field] w = wildcard_create_bit_repeat(len,0x1) for i in range(0,len): w[i] = i_wc[offset+i] out_string = "%s%s:%s, "%(out_string, field, w) return out_string
def parse_new_rule_tokens(tokens,mapf,rtr): in_ports = [] out_ports = [] match = wildcard_create_bit_repeat(HS_FORMAT["length"],0x3) mask = None rw = None for token in tokens: parts = token.split("=") field_name = parts[0] if field_name.startswith("new"): if mask == None: mask = wildcard_create_bit_repeat(HS_FORMAT["length"],0x2) rw = wildcard_create_bit_repeat(HS_FORMAT["length"],0x1) field_name = field_name[4:] if field_name in ["ip_src","ip_dst"]: [value,left_mask] = dotted_subnet_to_int(parts[1]) right_mask = 32 - left_mask else: value = int(parts[1]) right_mask = 0 set_header_field(cisco_router.HS_FORMAT(), mask, field_name, 0, right_mask) set_header_field(cisco_router.HS_FORMAT(), rw, field_name, value, right_mask) else: if field_name in ["in_ports","out_ports"]: ports = parts[1].split(",") ports_int = [] for port in ports: ports_int.append(int(mapf[rtr][port])) if field_name == "in_ports": in_ports = ports_int else: out_ports = ports_int else: if field_name in ["ip_src","ip_dst"]: [value,left_mask] = dotted_subnet_to_int(parts[1]) right_mask = 32 - left_mask else: value = int(parts[1]) right_mask = 0 set_header_field(cisco_router.HS_FORMAT(), match, field_name, value, right_mask) rule = TF.create_standard_rule(in_ports, match, out_ports, mask, rw, "", []) return rule
def detect_loop(NTF, TTF, ports, test_packet=None, out_port_offset=0): loops = [] for port in ports: print "port %d is being checked" % port propagation = [] # put all-x test packet in propagation graph test_pkt = test_packet if test_pkt == None: all_x = wildcard_create_bit_repeat(NTF.length, 0x3) test_pkt = headerspace(NTF.length) test_pkt.add_hs(all_x) p_node = {} p_node["hdr"] = test_pkt p_node["port"] = port p_node["visits"] = [] p_node["hs_history"] = [] propagation.append(p_node) while len(propagation) > 0: # get the next node in propagation graph and apply it to NTF and TTF print "Propagation has length: %d" % len(propagation) tmp_propag = [] for p_node in propagation: next_hp = NTF.T(p_node["hdr"], p_node["port"]) for (next_h, next_ps) in next_hp: for next_p in next_ps: linked = TTF.T(next_h, next_p) for (linked_h, linked_ports) in linked: for linked_p in linked_ports: new_p_node = {} new_p_node["hdr"] = linked_h new_p_node["port"] = linked_p new_p_node["visits"] = list(p_node["visits"]) new_p_node["visits"].append(p_node["port"]) # new_p_node["visits"].append(next_p) new_p_node["hs_history"] = list(p_node["hs_history"]) new_p_node["hs_history"].append(p_node["hdr"]) # print new_p_node if len(new_p_node["visits"]) > 0 and new_p_node["visits"][0] == linked_p: loops.append(new_p_node) print "loop detected" elif ( linked_p in new_p_node["visits"] or (linked_p + out_port_offset) in new_p_node["visits"] ): pass else: tmp_propag.append(new_p_node) propagation = tmp_propag return loops
def add_entry(self,wildcard_match,ports,obj): m = wildcard_create_bit_repeat(len(self.match_indices),1) for i in range(len(self.match_indices)): m[i] = wildcard_match[self.match_indices[i]] match_key_string = "%s"%m if 'x' in match_key_string: match_key_string = "default" for port in ports: if str(port) not in self.inport_to_table.keys(): self.inport_to_table[str(port)] = {} if match_key_string not in self.inport_to_table[str(port)].keys(): self.inport_to_table[str(port)][match_key_string] = [] self.inport_to_table[str(port)][match_key_string].append(obj)
def add_entry(self, wildcard_match, ports, obj): m = wildcard_create_bit_repeat(len(self.match_indices), 1) for i in range(len(self.match_indices)): m[i] = wildcard_match[self.match_indices[i]] match_key_string = "%s" % m if 'x' in match_key_string: match_key_string = "default" for port in ports: if str(port) not in self.inport_to_table.keys(): self.inport_to_table[str(port)] = {} if match_key_string not in self.inport_to_table[str(port)].keys(): self.inport_to_table[str(port)][match_key_string] = [] self.inport_to_table[str(port)][match_key_string].append(obj)
def make_header(h_desc): all_x = wildcard_create_bit_repeat(cisco_router.HS_FORMAT()["length"],0x3) parts = h_desc.split(",") fields = ["vlan", "ip_src", "ip_dst", "ip_proto", "transport_src", "transport_dst"] for part in parts: tmp = part.split("=") field = tmp[0] value = tmp[1] if field in ["ip_src","ip_dst"]: (ip,sub) = dotted_subnet_to_int(value) set_header_field(cisco_router.HS_FORMAT(), all_x, field, ip, 32-sub) else: set_header_field(cisco_router.HS_FORMAT(), all_x, field, int(value), 0) return all_x
def detect_loop(NTF, TTF, ports, test_packet = None, out_port_offset = 0): loops = [] for port in ports: print "port %d is being checked"%port propagation = [] # put all-x test packet in propagation graph test_pkt = test_packet if test_pkt == None: all_x = wildcard_create_bit_repeat(NTF.length,0x3) test_pkt = headerspace(NTF.length) test_pkt.add_hs(all_x) p_node = {} p_node["hdr"] = test_pkt p_node["port"] = port p_node["visits"] = [] p_node["hs_history"] = [] propagation.append(p_node) while len(propagation)>0: #get the next node in propagation graph and apply it to NTF and TTF print "Propagation has length: %d"%len(propagation) tmp_propag = [] for p_node in propagation: next_hp = NTF.T(p_node["hdr"],p_node["port"]) for (next_h,next_ps) in next_hp: for next_p in next_ps: linked = TTF.T(next_h,next_p) for (linked_h,linked_ports) in linked: for linked_p in linked_ports: new_p_node = {} new_p_node["hdr"] = linked_h new_p_node["port"] = linked_p new_p_node["visits"] = list(p_node["visits"]) new_p_node["visits"].append(p_node["port"]) #new_p_node["visits"].append(next_p) new_p_node["hs_history"] = list(p_node["hs_history"]) new_p_node["hs_history"].append(p_node["hdr"]) #print new_p_node if len(new_p_node["visits"]) > 0 and new_p_node["visits"][0] == linked_p: loops.append(new_p_node) print "loop detected" elif linked_p in new_p_node["visits"] or (linked_p + out_port_offset) in new_p_node["visits"]: pass else: tmp_propag.append(new_p_node) propagation = tmp_propag return loops
def acl_dict_entry_to_wc(self, dic_entry): result = [] result.append(wildcard_create_bit_repeat(self.hs_format["length"], 0x3)) if (dic_entry["ip_protocol"] != 0): self.set_field(result[0], "ip_proto", dic_entry["ip_protocol"], 0) self.set_field(result[0], "ip_src", dic_entry["src_ip"], find_num_mask_bits_right_mak(dic_entry["src_ip_mask"])) self.set_field(result[0], "ip_dst", dic_entry["dst_ip"], find_num_mask_bits_right_mak(dic_entry["dst_ip_mask"])) tp_src_matches = range_to_wildcard(dic_entry["transport_src_begin"], dic_entry["transport_src_end"], 16) tmp = [] for tp_src_match in tp_src_matches: w = wildcard_copy(result[0]) self.set_field(w, "tcp_src", tp_src_match[0], tp_src_match[1]) tmp.append(w) result = tmp tp_dst_matches = range_to_wildcard(dic_entry["transport_dst_begin"], dic_entry["transport_dst_end"], 16) tmp = [] for tp_dst_match in tp_dst_matches: for r in result: w = wildcard_copy(r) self.set_field(w, "tcp_dst", tp_dst_match[0], tp_dst_match[1]) tmp.append(w) result = tmp tp_ctrl_matches = range_to_wildcard(dic_entry["tcp_ctrl_begin"], dic_entry["tcp_ctrl_end"], 8) tmp = [] for tp_ctrl_matche in tp_ctrl_matches: for r in result: w = wildcard_copy(r) self.set_field(w, "tcp_ctrl", tp_ctrl_matche[0], tp_ctrl_matche[1]) tmp.append(w) result = tmp return result
g.read_nodes_xml("path_to_nodes.xml") settings = {"rtr_names":g.generate_node_names(), "num_layers":3, "fwd_engine_layer":2, "input_path":"tf_files", "switch_id_multiplier":cisco_router.SWITCH_ID_MULTIPLIER, "port_type_multiplier":cisco_router.PORT_TYPE_MULTIPLIER, "out_port_type_const":cisco_router.OUTPUT_PORT_TYPE_CONST, "remove_duplicates":True, } (ntf,ttf,name_to_id,id_to_name) = load_network(settings) # create all-x packet as input headerspace. all_x = wildcard_create_bit_repeat(ntf.length,0x3) # uncomment to set some field #set_header_field(cisco_router.HS_FORMAT(), all_x, "field", value, right_mask) #set_header_field(cisco_router.HS_FORMAT(), all_x, "vlan", 92, 0) test_pkt = headerspace(ntf.length) test_pkt.add_hs(all_x) #set some input/output ports output_port_addition = cisco_router.PORT_TYPE_MULTIPLIER * \ cisco_router.OUTPUT_PORT_TYPE_CONST #TODO: CHANGE THIS IF YOU WANT TO RUN IT FROM/TO DIFFERENT PORTS src_port_id = name_to_id["ROUTER NAME"]["PORT NAME"] dst_port_ids = [name_to_id["ROUTER NAME"]["PORT NAME"]+output_port_addition] #start reachability test and print results st = time()
if (not line.startswith("$")) and line != "": tokens = line.strip().split(":") port = int(tokens[1]) + settings["port_type_multiplier"] * \ settings["mid_port_type_const"] N.add_link(port,port) # add link for forward engine port for i in range(len(settings["rtr_names"])): fwd_link = (i+1) * settings["switch_id_multiplier"] N.add_link(fwd_link,fwd_link) # add a source node at yoza-te1/4 src_port_id = map["yoza_rtr"]["te1/4"] N.add_link(1,src_port_id) hs = headerspace(N.length) hs.add_hs(wildcard_create_bit_repeat(N.length,0x3)) N.add_source("yoza-source", hs, [1]) rule_ids = [] for rtr_name in settings["rtr_names"]: f = TF(1) f.load_object_from_file("%s/%s.tf"%(settings["input_path"],rtr_name)) for rule in f.rules: in_ports = rule["in_ports"] out_ports = rule["out_ports"] match = rule["match"] mask = rule["mask"] rewrite = rule["rewrite"] st = time() rule_ids.append(\ N.add_rule(rtr_name, -1, in_ports, out_ports, match, mask, rewrite)\
def generate_transfer_function(self, tf): ''' After calling read_config_file(), read_spanning_tree_file() and read_route_file(), generate_port_ids(), and optionally optimize_forwarding_table(), this method may be called to generate transfer function rules corresponding to this box. The rules will be added to transfer function tf passed to the function. ''' print "=== Generating Transfer Function ===" # generate the input part of tranfer function from in_port to fwd_port # and output part from intermedite ports to output ports print " * Generating ACL transfer function * " for acl in self.acl_iface.keys(): if acl not in self.acl.keys(): continue for acl_instance in self.acl_iface[acl]: file_name = acl_instance[3] specified_ports = [] vlan = acl_instance[2] if acl_instance[0].startswith("vlan"): for p in self.vlan_ports[acl_instance[0]]: specified_ports.append(self.port_to_id[p]) else: specified_ports = [self.port_to_id(acl_instance[0])] for acl_dic_entry in self.acl[acl]: matches = self.acl_dict_entry_to_wc(acl_dic_entry) lines = acl_instance[4] lines.extend(acl_dic_entry["line"]) # in acl entry if acl_instance[1] == "in": in_ports = specified_ports out_ports = [] if (acl_dic_entry["action"]): out_ports = [self.switch_id * self.SWITCH_ID_MULTIPLIER] for match in matches: self.set_field(match, "vlan", vlan, 0) next_rule = TF.create_standard_rule(in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) # out acl entry else: for match in matches: self.set_field(match, "vlan", vlan, 0) if (not acl_dic_entry["action"]): out_ports = [] in_ports = [] for port in specified_ports: in_ports.append(port+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) next_rule = TF.create_standard_rule(in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) else: for port in specified_ports: in_ports = [port+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST] out_ports = [port+self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST] next_rule = TF.create_standard_rule(in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) # default rule for all vlans configured on this switch and un-vlan-tagged ports intermediate_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] for cnf_vlan in self.config_vlans: if self.vlan_ports.has_key("vlan%d"%cnf_vlan): match = wildcard_create_bit_repeat(self.hs_format["length"],0x3) self.set_field(match, "vlan", cnf_vlan, 0) all_in_ports = [] for port in self.vlan_ports["vlan%d"%cnf_vlan]: all_in_ports.append(self.port_to_id[port]) def_rule = TF.create_standard_rule(all_in_ports, match, intermediate_port, None, None, "", []) tf.add_fwd_rule(def_rule) # ... un-vlan-tagged port all_in_ports = [] for port in self.port_to_id.keys(): if port != "self": all_in_ports.append(self.port_to_id[port]) # match = byte_array_get_all_x(self.hs_format["length"]*2) # self.set_field(match, "vlan", 0, 0) # def_rule = TF.create_standard_rule(all_in_ports, match, intermediate_port, None, None, "", []) # tf.add_fwd_rule(def_rule) # default rule from intermediate port to outut port match = wildcard_create_bit_repeat(self.hs_format["length"],0x3) for port_id in all_in_ports: before_out_port = [port_id+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST] after_out_port = [port_id+self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST] def_rule = TF.create_standard_rule(before_out_port, match, after_out_port , None, None, "", []) # James: No default output ACL #tf.add_fwd_rule(def_rule) ################################## # print " * Generating VLAN forwarding transfer function... * " # # generate VLAN forwarding entries # for vlan_num in self.port_subnets.keys(): # #James: if VLAN has only one port, don't worry about forwarding! # vlan = int(vlan_num) # if "vlan%d"%vlan in self.vlan_ports.keys(): # if(len(self.vlan_ports["vlan%d"%vlan]) == 1): # #print "Found orphant VLAN %s on port %s" %(vlan_num, self.vlan_ports["vlan%d"%int(vlan_num)]) # continue # #end of James' magic :P # for (ip_addr,subnet_mask,file_name,lines,port) in self.port_subnets[vlan_num]: # match = byte_array_get_all_x(self.hs_format["length"]*2) # in_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] # vlan = int(vlan_num) # out_ports = [] # if ip_addr == None: # self.set_field(match, "vlan", vlan, 0) # else: # self.set_field(match, "ip_dst", ip_addr, subnet_mask) # self.set_field(match, "vlan", vlan, 0) # if not port.startswith("vlan"): # out_ports.append(self.port_to_id[port]+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) # elif "vlan%d"%vlan in self.vlan_ports.keys(): # port_list = self.vlan_ports["vlan%d"%vlan] # for p in port_list: # out_ports.append(self.port_to_id[p]+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) # tf_rule = TF.create_standard_rule(in_port, match, out_ports, None, None,file_name,lines) # tf.add_fwd_rule(tf_rule) ################################### print " * Generating IP forwarding transfer function... * " self.fwd_table.sort(key=lambda fwd_rule: fwd_rule[1], reverse=True) # generate the forwarding part of transfer fucntion, from the fwd_prt, to pre-output ports for subnet in range(32,-1,-1): while [] in self.fwd_table: self.fwd_table.remove([]) for fwd_rule in self.fwd_table: index = self.fwd_table.index(fwd_rule) if fwd_rule[1] != subnet: break else: #in -ports and match bytearray match = wildcard_create_bit_repeat(self.hs_format["length"],0x3) self.set_field(match, "ip_dst", int(fwd_rule[0]), 32-subnet) in_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] # mask, rewrite mask = wildcard_create_bit_repeat(self.hs_format["length"],0x2) rewrite = wildcard_create_bit_repeat(self.hs_format["length"],0x1) # find out the file-line it represents: lines = [] file_name = "" if len(fwd_rule) == 4: for c_rule in fwd_rule[3]: file_name = c_rule[3] lines.extend(c_rule[4]) else: file_name = fwd_rule[3] lines.extend(fwd_rule[4]) # set up out_ports out_ports = [] # fwd_rule[2] is a list, thanks to LAG for output_port in fwd_rule[2]: vlan = 0 m = re.split('\.',output_port) # drop rules: if output_port == "self": self_rule = TF.create_standard_rule(in_port,match,[],None,None,file_name,lines) tf.add_fwd_rule(self_rule) # non drop rules else: # sub-ports: port.vlan if len(m) > 1: if m[0] in self.port_to_id.keys(): out_ports.append(self.port_to_id[m[0]]+self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = int(m[1]) else: print "ERROR: unrecognized port %s"%m[0] return -1 # vlan outputs elif output_port.startswith('vlan'): if output_port in self.vlan_ports.keys(): port_list = self.vlan_ports[output_port] for p in port_list: out_ports.append(self.port_to_id[p]+self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = int(output_port[4:]) else: print "ERROR: unrecognized vlan %s"%output_port return -1 # physical ports - no vlan taging else: if output_port in self.port_to_id.keys(): out_ports.append(self.port_to_id[output_port] + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = 0 else: print "ERROR: unrecognized port %s"%output_port return -1 # now set the fields self.set_field(mask, 'vlan', 0, 0) self.set_field(rewrite, 'vlan', vlan, 0) tf_rule = TF.create_standard_rule(in_port, match, out_ports, mask, rewrite,file_name,lines) tf.add_rewrite_rule(tf_rule) self.fwd_table[index] = [] #Invalidate fwd_rule print "=== Successfully Generated Transfer function ===" #print tf return 0
if (not line.startswith("$")) and line != "": tokens = line.strip().split(":") port = int(tokens[1]) + settings["port_type_multiplier"] * \ settings["mid_port_type_const"] N.add_link(port, port) # add link for forward engine port for i in range(len(settings["rtr_names"])): fwd_link = (i + 1) * settings["switch_id_multiplier"] N.add_link(fwd_link, fwd_link) # add a source node at yoza-te1/4 src_port_id = map["yoza_rtr"]["te1/4"] N.add_link(1, src_port_id) hs = headerspace(N.length) hs.add_hs(wildcard_create_bit_repeat(N.length, 0x3)) N.add_source("yoza-source", hs, [1]) rule_ids = [] for rtr_name in settings["rtr_names"]: f = TF(1) f.load_object_from_file("%s/%s.tf" % (settings["input_path"], rtr_name)) for rule in f.rules: in_ports = rule["in_ports"] out_ports = rule["out_ports"] match = rule["match"] mask = rule["mask"] rewrite = rule["rewrite"] st = time() rule_ids.append(\ N.add_rule(rtr_name, -1, in_ports, out_ports, match, mask, rewrite)\
def generate_transfer_function(self, tf): ''' After calling read_config_file(), read_spanning_tree_file() and read_route_file(), generate_port_ids(), and optionally optimize_forwarding_table(), this method may be called to generate transfer function rules corresponding to this box. The rules will be added to transfer function tf passed to the function. ''' print "=== Generating Transfer Function ===" # generate the input part of tranfer function from in_port to fwd_port # and output part from intermedite ports to output ports print " * Generating ACL transfer function * " for acl in self.acl_iface.keys(): if acl not in self.acl.keys(): continue for acl_instance in self.acl_iface[acl]: file_name = acl_instance[3] specified_ports = [] vlan = acl_instance[2] if acl_instance[0].startswith("vlan"): for p in self.vlan_ports[acl_instance[0]]: specified_ports.append(self.port_to_id[p]) else: specified_ports = [self.port_to_id(acl_instance[0])] for acl_dic_entry in self.acl[acl]: matches = self.acl_dict_entry_to_wc(acl_dic_entry) lines = acl_instance[4] lines.extend(acl_dic_entry["line"]) # in acl entry if acl_instance[1] == "in": in_ports = specified_ports out_ports = [] if (acl_dic_entry["action"]): out_ports = [ self.switch_id * self.SWITCH_ID_MULTIPLIER ] for match in matches: self.set_field(match, "vlan", vlan, 0) next_rule = TF.create_standard_rule( in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) # out acl entry else: for match in matches: self.set_field(match, "vlan", vlan, 0) if (not acl_dic_entry["action"]): out_ports = [] in_ports = [] for port in specified_ports: in_ports.append( port + self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) next_rule = TF.create_standard_rule( in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) else: for port in specified_ports: in_ports = [ port + self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST ] out_ports = [ port + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST ] next_rule = TF.create_standard_rule( in_ports, match, out_ports, None, None, file_name, lines) tf.add_fwd_rule(next_rule) # default rule for all vlans configured on this switch and un-vlan-tagged ports intermediate_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] for cnf_vlan in self.config_vlans: if self.vlan_ports.has_key("vlan%d" % cnf_vlan): match = wildcard_create_bit_repeat(self.hs_format["length"], 0x3) self.set_field(match, "vlan", cnf_vlan, 0) all_in_ports = [] for port in self.vlan_ports["vlan%d" % cnf_vlan]: all_in_ports.append(self.port_to_id[port]) def_rule = TF.create_standard_rule(all_in_ports, match, intermediate_port, None, None, "", []) tf.add_fwd_rule(def_rule) # ... un-vlan-tagged port all_in_ports = [] for port in self.port_to_id.keys(): if port != "self": all_in_ports.append(self.port_to_id[port]) # match = byte_array_get_all_x(self.hs_format["length"]*2) # self.set_field(match, "vlan", 0, 0) # def_rule = TF.create_standard_rule(all_in_ports, match, intermediate_port, None, None, "", []) # tf.add_fwd_rule(def_rule) # default rule from intermediate port to outut port match = wildcard_create_bit_repeat(self.hs_format["length"], 0x3) for port_id in all_in_ports: before_out_port = [ port_id + self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST ] after_out_port = [ port_id + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST ] def_rule = TF.create_standard_rule(before_out_port, match, after_out_port, None, None, "", []) # James: No default output ACL #tf.add_fwd_rule(def_rule) ################################## # print " * Generating VLAN forwarding transfer function... * " # # generate VLAN forwarding entries # for vlan_num in self.port_subnets.keys(): # #James: if VLAN has only one port, don't worry about forwarding! # vlan = int(vlan_num) # if "vlan%d"%vlan in self.vlan_ports.keys(): # if(len(self.vlan_ports["vlan%d"%vlan]) == 1): # #print "Found orphant VLAN %s on port %s" %(vlan_num, self.vlan_ports["vlan%d"%int(vlan_num)]) # continue # #end of James' magic :P # for (ip_addr,subnet_mask,file_name,lines,port) in self.port_subnets[vlan_num]: # match = byte_array_get_all_x(self.hs_format["length"]*2) # in_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] # vlan = int(vlan_num) # out_ports = [] # if ip_addr == None: # self.set_field(match, "vlan", vlan, 0) # else: # self.set_field(match, "ip_dst", ip_addr, subnet_mask) # self.set_field(match, "vlan", vlan, 0) # if not port.startswith("vlan"): # out_ports.append(self.port_to_id[port]+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) # elif "vlan%d"%vlan in self.vlan_ports.keys(): # port_list = self.vlan_ports["vlan%d"%vlan] # for p in port_list: # out_ports.append(self.port_to_id[p]+self.PORT_TYPE_MULTIPLIER * self.INTERMEDIATE_PORT_TYPE_CONST) # tf_rule = TF.create_standard_rule(in_port, match, out_ports, None, None,file_name,lines) # tf.add_fwd_rule(tf_rule) ################################### print " * Generating IP forwarding transfer function... * " self.fwd_table.sort(key=lambda fwd_rule: fwd_rule[1], reverse=True) # generate the forwarding part of transfer fucntion, from the fwd_prt, to pre-output ports for subnet in range(32, -1, -1): while [] in self.fwd_table: self.fwd_table.remove([]) for fwd_rule in self.fwd_table: index = self.fwd_table.index(fwd_rule) if fwd_rule[1] != subnet: break else: #in -ports and match bytearray match = wildcard_create_bit_repeat( self.hs_format["length"], 0x3) self.set_field(match, "ip_dst", int(fwd_rule[0]), 32 - subnet) in_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] # mask, rewrite mask = wildcard_create_bit_repeat(self.hs_format["length"], 0x2) rewrite = wildcard_create_bit_repeat( self.hs_format["length"], 0x1) # find out the file-line it represents: lines = [] file_name = "" if len(fwd_rule) == 4: for c_rule in fwd_rule[3]: file_name = c_rule[3] lines.extend(c_rule[4]) else: file_name = fwd_rule[3] lines.extend(fwd_rule[4]) # set up out_ports out_ports = [] # fwd_rule[2] is a list, thanks to LAG for output_port in fwd_rule[2]: vlan = 0 m = re.split('\.', output_port) # drop rules: if output_port == "self": self_rule = TF.create_standard_rule( in_port, match, [], None, None, file_name, lines) tf.add_fwd_rule(self_rule) # non drop rules else: # sub-ports: port.vlan if len(m) > 1: if m[0] in self.port_to_id.keys(): out_ports.append( self.port_to_id[m[0]] + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = int(m[1]) else: print "ERROR: unrecognized port %s" % m[0] return -1 # vlan outputs elif output_port.startswith('vlan'): if output_port in self.vlan_ports.keys(): port_list = self.vlan_ports[output_port] for p in port_list: out_ports.append( self.port_to_id[p] + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = int(output_port[4:]) else: print "ERROR: unrecognized vlan %s" % output_port return -1 # physical ports - no vlan taging else: if output_port in self.port_to_id.keys(): out_ports.append( self.port_to_id[output_port] + self.PORT_TYPE_MULTIPLIER * self.OUTPUT_PORT_TYPE_CONST) vlan = 0 else: print "ERROR: unrecognized port %s" % output_port return -1 # now set the fields self.set_field(mask, 'vlan', 0, 0) self.set_field(rewrite, 'vlan', vlan, 0) tf_rule = TF.create_standard_rule( in_port, match, out_ports, mask, rewrite, file_name, lines) tf.add_rewrite_rule(tf_rule) self.fwd_table[index] = [] #Invalidate fwd_rule print "=== Successfully Generated Transfer function ===" #print tf return 0