Source code for sts.headerspace.config_parser.cisco_router_parser

'''
Created on May 11, 2011

@author: peymankazemian
'''
from helper import *
from sts.headerspace.headerspace.tf import *
from sts.headerspace.headerspace.hs import *
import re

[docs]class ciscoRouter(object): ''' Cisco router parser. The generated transfer function will have three sub-layers: 1) from input port to fwd port: the packet will go through input acl, and vlan untag process 2) from fwd port to pre-output port: the forwarding table will find output port. but the output filter has not been applied yet. 3) from pre-output port to output port: this is where output acl filter is being done. So in order to see the ultimate faith of packet, we need to apply the tf.T() 3 consequative times. ''' PORT_ID_MULTIPLIER = 1 PORT_TYPE_MULTIPLIER = 10000 SWITCH_ID_MULTIPLIER = 100000
[docs] def __init__(self, switch_id): ''' Constructor ''' # for each acl number has a list of acl dictionary entries self.acl = {} # for each vlan holds the list of ports in its spanning tree self.vlan_ports = {} # for each port/vlan hold the ip address and subnet pair that is configured on it. self.port_subnets = {} # forwarding table self.fwd_table = [] # arp and mac table self.arp_table = {} self.mac_table = {} # for each interface, we have (access-list#, in/out, file, line) self.acl_iface = {} # list of vlans configured on this switch self.config_vlans = [] # list of ports configured on this switch self.config_ports = set() self.switch_id = switch_id self.port_to_id = {} self.hs_format = self.HS_FORMAT() self.replaced_vlan = 0
[docs] def set_replaced_vlan(self,vlan): self.replaced_vlan = vlan
@staticmethod
[docs] def HS_FORMAT(): format = {} format["vlan_pos"] = 0 format["ip_src_pos"] = 2 format["ip_dst_pos"] = 6 format["ip_proto_pos"] = 10 format["tcp_src_pos"] = 11 format["tcp_dst_pos"] = 13 format["tcp_ctrl_pos"] = 15 format["vlan_len"] = 2 format["ip_src_len"] = 4 format["ip_dst_len"] = 4 format["ip_proto_len"] = 1 format["tcp_src_len"] = 2 format["tcp_dst_len"] = 2 format["tcp_ctrl_len"] = 1 format["length"] = 16 return format
[docs] def wc_to_parsed_string(self, byte_arr): fields = ["vlan","ip_src","ip_dst","ip_proto","tcp_src","tcp_dst","tcp_ctrl"] out_string = "" for field in fields: offset = self.hs_format["%s_pos"%field] len = self.hs_format["%s_len"%field] ba = bytearray() for i in range(0,len): ba.append(byte_arr[offset+i]) out_string = "%s%s:%s, "%(out_string, field, byte_array_to_hs_string(ba)) return out_string
[docs] def set_field(self, arr, field, value, right_mask): ''' Sets the field in byte array arr to value. @arr: the bytearray to set the field bits to value. @field: 'vlan', 'ip_src', 'ip_dst', 'ip_proto', 'tcp_src', 'tcp_dst', 'tcp_ctrl' @value: an integer number, of the width equal to field's width @right_mask: number of bits, from right that should be ignored when written to field. e.g. to have a /24 ip address, set mask to 8. ''' b_array = int_to_byte_array(value,8*self.hs_format["%s_len"%field]) start_pos = 2*self.hs_format["%s_pos"%field] for i in range(2*self.hs_format["%s_len"%field]): if right_mask <= 4*i: arr[start_pos + i] = b_array[i] elif (right_mask > 4*i and right_mask < 4*i + 4): shft = right_mask % 4; rm = (0xff << 2*shft) & 0xff lm = ~rm & 0xff arr[start_pos + i] = (b_array[i] & rm) | (arr[start_pos + i] & lm)
[docs] def set_witch_id(self, switch_id): self.switch_id = switch_id
[docs] def get_switch_id(self): return self.switch_id
[docs] def set_hs_format(self, hs_format): self.hs_format = hs_format
@staticmethod
[docs] def make_acl_dictionary_entry(): entry = {} entry["action"] = True entry["src_ip"] = 0 entry["src_ip_mask"] = 0xffffffff entry["dst_ip"] = 0 entry["dst_ip_mask"] = 0xffffffff entry["ip_protocol"] = 0 # Note: this is used instead of any ip protocol entry["transport_src_begin"] = 0 entry["transport_src_end"] = 0xffff entry["transport_dst_begin"] = 0 entry["transport_dst_end"] = 0xffff entry["tcp_ctrl_begin"] = 0 entry["tcp_ctrl_end"] = 0xff return entry
[docs] def acl_dictionary_entry_to_bytearray(self,dic_entry): result = [] result.append(byte_array_get_all_x(self.hs_format["length"]*2)) 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: b = bytearray(result[0]) self.set_field(b, "tcp_src", tp_src_match[0], tp_src_match[1]) tmp.append(b) 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: b = bytearray(r) self.set_field(b, "tcp_dst", tp_dst_match[0], tp_dst_match[1]) tmp.append(b) 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: b = bytearray(r) self.set_field(b, "tcp_ctrl", tp_ctrl_matche[0], tp_ctrl_matche[1]) tmp.append(b) result = tmp return result
@staticmethod
[docs] def acl_dictionary_entry_to_string(entry): output = "" if entry["action"]: output = "permit " else: output = "deny " output = output + "ip protocol: %d -- src ip: %s -- src ip mask: %s -- src transport port: %d-%d -- dst ip: %s -- dst ip mask: %s -- dst transport port: %d-%d"%(entry["ip_protocol"], int_to_dotted_ip(entry["src_ip"]),int_to_dotted_ip(entry["src_ip_mask"]),entry["transport_src_begin"],entry["transport_src_end"], int_to_dotted_ip(entry["dst_ip"]),int_to_dotted_ip(entry["dst_ip_mask"]),entry["transport_dst_begin"],entry["transport_dst_end"], ) return output;
@staticmethod
[docs] def get_protocol_number(proto_name): dict = {"ah":51, "eigrp":88, "esp":50, "gre":47, "icmp":1, "igmp":2, "igrp":9, "ip": 0, "ipinip":94, "nos":4, "ospf":89, "tcp":6, "udp":17} if proto_name in dict.keys(): return dict[proto_name] else: try: num = int(proto_name) return num except Exception as e: return None
@staticmethod
[docs] def get_udp_port_number(port_name): dict = {"biff": 512, "bootpc":68, "bootps":69, "discard":9, "domain":53, "dnsix":90, "echo":7, "mobile-ip":434, "nameserver":42, "netbios-dgm":137, "netbios-ns":138, "ntp":123, "rip":520, "snmp":161, "snmptrap":162, "sunrpc":111, "syslog":514, "tacacs-ds":49, "talk":517, "tftp":69, "time":37, "who":513, "xdmcp":177} if port_name in dict.keys(): return dict[port_name] else: try: num = int(port_name) return num except Exception as e: return None
@staticmethod
[docs] def get_tcp_port_number(port_name): dict = {"bgp":179, "chargen":19, "daytime":13, "discard":9, "domain":53, "echo":7, "finger":79, "ftp":21, "ftp-data":20, "gopher":70, "hostname":101, "irc":194, "klogin":543, "kshell":544, "lpd":515, "nntp":119, "pop2":109, "pop3":110, "smtp":25, "sunrpc":111, "syslog":514, "tacacs-ds":65, "talk":517, "telnet":23, "time": 37, "uucp":540, "whois":43, "www":80} if port_name in dict.keys(): return dict[port_name] else: try: num = int(port_name) return num except Exception as e: return None
@staticmethod
[docs] def get_transport_port_number(port): try: num = int(port) return num except Exception as e: return None
@staticmethod
[docs] def get_ethernet_port_name(port): result = "" reminder = "" if port.lower().startswith("tengigabitethernet"): result = "te" reminder = port[len("tengigabitethernet"):] elif port.lower().startswith("gigabitethernet"): result = "gi" reminder = port[len("gigabitethernet"):] elif port.lower().startswith("fastethernet"): result = "fa" reminder = port[len("fastethernet"):] else: result = port return "%s%s"%(result, reminder)
[docs] def parse_access_list_entry(self, entry, line_counter): def parse_ip(lst): result = {} if lst[0].lower() == "any": result["ip"] = 0 result["ip_mask"] = 0xffffffff lst.pop(0) elif lst[0].lower() == "host": result["ip"] = dotted_ip_to_int(lst[1]) result["ip_mask"] = 0 lst.pop(0) lst.pop(0) elif is_ip_address(lst[0]): result["ip"] = dotted_ip_to_int(lst[0]) if len(lst) > 1 and is_ip_address(lst[1]): result["ip_mask"] = dotted_ip_to_int(lst[1]) lst.pop(0) lst.pop(0) else: result["ip_mask"] = 0 lst.pop(0) return result def parse_port(lst, proto): result = {} proto_reader = None if proto == 6: proto_reader = ciscoRouter.get_tcp_port_number elif proto == 17: proto_reader = ciscoRouter.get_udp_port_number else: proto_reader = ciscoRouter.get_transport_port_number if lst[0] == "eq": lst.pop(0) p = proto_reader(lst.pop(0)) if p != None: result["port_begin"] = p result["port_end"] = p elif lst[0] == "gt": lst.pop(0) p = proto_reader(lst.pop(0)) if p != None: result["port_begin"] = p + 1 result["port_end"] = 0xffff elif lst[0] == "range": lst.pop(0) p1 = proto_reader(lst.pop(0)) p2 = proto_reader(lst.pop(0)) if p1 != None and p2 != None: result["port_begin"] = p1 result["port_end"] = p2 return result tokens = entry.split() tokens.pop(0) acl_number = tokens.pop(0) acl_number_int = int(acl_number) action = tokens.pop(0) if action.lower() == "permit" or action.lower() == "deny": if not acl_number in self.acl.keys(): self.acl[acl_number] = [] new_entry = self.make_acl_dictionary_entry() new_entry["action"] = (action.lower() == "permit") # standard access-list entry if acl_number_int < 100: new_entry["ip_protocol"] = 0 new_ip = parse_ip(tokens) if (len(new_ip.keys()) > 0): new_entry["src_ip"] = new_ip["ip"] new_entry["src_ip_mask"] = new_ip["ip_mask"] self.acl[acl_number].append(new_entry) #print self.acl_dictionary_entry_to_string(new_entry) return True else: return False # extended access-list entry else: if self.get_protocol_number(tokens[0]) != None: new_entry["ip_protocol"] = self.get_protocol_number(self.get_protocol_number(tokens.pop(0))) elif is_ip_address(tokens[0]): new_entry["ip_protocol"] = 0 else: return False # src ip address and ip mask new_ip = parse_ip(tokens) if (len(new_ip.keys()) > 0): new_entry["src_ip"] = new_ip["ip"] new_entry["src_ip_mask"] = new_ip["ip_mask"] # src transport port number if len(tokens) > 0: new_ports = parse_port(tokens, new_entry["ip_protocol"]) if len(new_ports.keys()) > 0: new_entry["transport_src_begin"] = new_ports["port_begin"] new_entry["transport_src_end"] = new_ports["port_end"] # dst ip address and ip mask if len(tokens) > 0: new_ip = parse_ip(tokens) if (len(new_ip.keys()) > 0): new_entry["dst_ip"] = new_ip["ip"] new_entry["dst_ip_mask"] = new_ip["ip_mask"] # dst transport port number if len(tokens) > 0: new_ports = parse_port(tokens, new_entry["ip_protocol"]) if len(new_ports.keys()) > 0: new_entry["transport_dst_begin"] = new_ports["port_begin"] new_entry["transport_dst_end"] = new_ports["port_end"] # tcp control bits if len(tokens) > 0: t = tokens.pop(0) if t == "established": new_entry["tcp_ctrl_begin"] = 0x80 new_entry["tcp_ctrl_end"] = 0xff new_entry["line"] = [line_counter]; self.acl[acl_number].append(new_entry) #print self.acl_dictionary_entry_to_string(new_entry) return True
[docs] def read_config_file(self, file_path): ''' Reads in the CISCO router config file and extracts access list entries and the ports/vlans they apply to. ''' print "=== Reading Cisco Router Config File ===" f = open(file_path,'r') last_iface = "" last_vlan = None line_counter = 0; for line in f: line = line.strip() # read an access-list line if line.startswith("access-list"): self.parse_access_list_entry(line,line_counter) elif line.startswith("interface"): tokens = line.split() last_iface = ciscoRouter.get_ethernet_port_name(tokens[1].lower()) if last_iface.startswith("vlan"): last_vlan = int(last_iface[4:]) self.config_vlans.append(last_vlan) else: parts = re.split('\.',last_iface) if len(parts) > 1: last_vlan = int(parts[1]) last_iface = parts[0] self.config_vlans.append(last_vlan) if not "vlan%d"%last_vlan in self.vlan_ports.keys(): self.vlan_ports["vlan%d"%last_vlan] = [] self.vlan_ports["vlan%d"%last_vlan].append(last_iface) else: last_vlan = None self.config_ports.add(last_iface) if last_vlan != None and "%d"%last_vlan not in self.port_subnets.keys(): self.port_subnets["%d"%last_vlan] = [] elif line.startswith("ip access-group"): tokens = line.split() if not tokens[2] in self.acl_iface.keys(): self.acl_iface[tokens[2]] = [] self.acl_iface[tokens[2]].append((last_iface,tokens[3],last_vlan,file_path,[line_counter])) elif line.startswith("no ip address"): if last_vlan != None: self.port_subnets["%d"%last_vlan].append((None,None,file_path,[line_counter],last_iface)) elif line.startswith("ip address"): tokens = line.split() if last_vlan != None: ip_int = dotted_ip_to_int(tokens[2]) mask_int = find_num_mask_bits_left_mak(dotted_ip_to_int(tokens[3])) self.port_subnets["%d"%last_vlan].append((ip_int, 32-mask_int, file_path, [line_counter], last_iface)) elif line.startswith("shutdown") and last_vlan != None: self.config_vlans.remove(last_vlan) del self.port_subnets["%d"%last_vlan] line_counter = line_counter + 1 f.close() #print self.port_subnets #print self.acl #print self.acl_iface print "=== DONE Reading Cisco Router Config File ==="
[docs] def read_spanning_tree_file(self, file_path): ''' Reads in, the CISCO router "sh spanning-tree" output and extracts the list of ports that are in FWD mode for each vlan. ''' print "=== Reading Cisco Router Spanning Tree File ===" current_vlan = 0 f = open(file_path,'r') for line in f: tokens = line.split() if len(tokens) == 0: continue if line.startswith("VLAN"): if len(tokens) == 1: current_vlan = "vlan%d"%int(tokens[0][4:]) self.vlan_ports[current_vlan] = [] elif (("FWD" in tokens) or ("fwd" in tokens)): self.vlan_ports[current_vlan].append(tokens[0].lower()) f.close() #print self.vlan_ports print "=== DONE Reading Cisco Router Spanning Tree File ==="
[docs] def read_arp_table_file(self, file_path): ''' Reads in CISCO router arp table - sh arp ''' print "=== Reading Cisco Router ARP Table File ===" f = open(file_path,'r') for line in f: tokens = line.split() if (len(tokens) >= 6 and tokens[4].lower() == "arpa"): self.arp_table[tokens[1]] = (tokens[3].lower(),tokens[5].lower()) f.close() print "=== DONE Reading Cisco Router ARP Table File ==="
[docs] def read_mac_table_file(self, file_path): ''' Reads in CISCO mac address table - sh mac-address-table ''' print "=== Reading Cisco Mac Address Table File ===" f = open(file_path,'r') seen_star = False ports = [] mac = "" for line in f: tokens = line.split() if (line.startswith("*")): if (seen_star): self.mac_table[mac] = ports ports = [] mac = "vlan%s,%s"%(tokens[1],tokens[2]) seen_star = True if (len(tokens) >= 7): ports.extend(tokens[6].split(",")) elif (seen_star): ports.extend(tokens[0].split(",")) self.mac_table[mac] = ports print "=== DONE Reading Cisco Mac Address Table File ==="
[docs] def read_route_file(self, file_path): ''' Reads in the CISCO router "sh ip cef" output and extracts the forwarding table entries. ''' print "=== Reading Cisco Router IP CEF File ===" f = open(file_path,'r') port = "" line_counter = 0; for line in f: tokens = line.split() if len(tokens) == 0: continue if is_ip_subnet(tokens[0]): ip_subnet = dotted_subnet_to_int(tokens[0]) if len(tokens) > 2: port = ciscoRouter.get_ethernet_port_name(tokens[2]) # next hop is a vlan, but also we know the ip adress. in this case we should find out which vlan port has that ip address if port.lower().startswith("vlan") and is_ip_address(tokens[1]): # look up next hop IP address in arp table to find the mac address and output port if (tokens[1] in self.arp_table.keys()): (mac,vln) = self.arp_table[tokens[1]] # if next hop output port is a vlan, look it up in mac table if vln.startswith("vlan"): vm_key = "%s,%s"%(vln,mac) # if mac-address-table for that vlan has the mac address, find out the port if vm_key in self.mac_table.keys(): resolved_port = self.mac_table[vm_key][0] vlan_num = int(vln[4:]) port = "%s.%d"%(ciscoRouter.get_ethernet_port_name(resolved_port),vlan_num) # if next hop output port is not vlan, use it else: port = ciscoRouter.get_ethernet_port_name(vln) # next hop is an attached vlan elif port.lower().startswith("vlan"): vlan = int(port[4:]) else: parts = re.split('\.',port) if len(parts) > 1 and self.replaced_vlan != 0: port = "%s.%d"%(parts[0],self.replaced_vlan) vlan = self.replaced_vlan elif len(parts) > 1: vlan = int(parts[1]) else: port = "self" if port.lower().startswith("loopback") or port.lower().startswith("null") or tokens[1].lower().startswith("drop"): port = "self" self.fwd_table.append([ip_subnet[0],ip_subnet[1],port.lower(),file_path,[line_counter]]) line_counter = line_counter + 1 f.close() #print self.fwd_table print "=== DONE Reading Cisco Router IP CEF File ==="
[docs] def generate_port_ids(self, additional_ports): ''' looks at all the ports that has FWD mode for any vlan or appear as forwarding port of a forwarding rule, and assign a unique ID to them based on switch_id and a random port id. addition_ports will also be considered and assigned a unqie ID. This is for ports that exist on the switch but are not part of any vlan or output of forwarding rules. ''' print "=== Generating port IDs ===" s = set(additional_ports) for elem in self.config_ports: s.add(elem) suffix = 1 for p in s: id = self.switch_id * self.SWITCH_ID_MULTIPLIER + suffix * self.PORT_ID_MULTIPLIER self.port_to_id[p] = id suffix += 1 #print self.port_to_id print "=== DONE generating port IDs ==="
[docs] def get_port_id(self,port_name): if port_name in self.port_to_id.keys(): return self.port_to_id[port_name] else: return None
[docs] def optimize_forwarding_table(self): print "=== Compressing forwarding table ===" print " * Originally has %d ip fwd entries * "%len(self.fwd_table) n = compress_ip_list(self.fwd_table) print " * After compression has %d ip fwd entries * "%len(n) self.fwd_table = n ''' for elem in n: str = "%s/%d: action: %s compressing: "%(int_to_dotted_ip(elem[0]) , elem[1], elem[2]) for e in elem[3]: str = str + int_to_dotted_ip(e[0]) + "/%d, "%e[1] print str ''' print "=== DONE forwarding table compression ==="
[docs] 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_dictionary_entry_to_bytearray(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) 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] out_ports = [port] 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 = byte_array_get_all_x(self.hs_format["length"]*2) 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 = byte_array_get_all_x(self.hs_format["length"]*2) for port_id in all_in_ports: before_out_port = [port_id+self.PORT_TYPE_MULTIPLIER] def_rule = TF.create_standard_rule(before_out_port, match, [port_id] , None, None, "", []) tf.add_fwd_rule(def_rule) ################################## print " * Generating VLAN forwarding transfer function... * " # generate VLAN forwarding entries for vlan_num in self.port_subnets.keys(): 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) 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) 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... * " # generate the forwarding part of transfer fucntion, from the fwd_prt, to pre-output ports for subnet in range(32,-1,-1): for fwd_rule in self.fwd_table: if fwd_rule[1] == subnet: #in -ports and match bytearray match = byte_array_get_all_x(self.hs_format["length"]*2) self.set_field(match, "ip_dst", int(fwd_rule[0]), 32-subnet) in_port = [self.switch_id * self.SWITCH_ID_MULTIPLIER] # mask, rewrite mask = byte_array_get_all_one(self.hs_format["length"]*2) rewrite = byte_array_get_all_zero(self.hs_format["length"]*2) # 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 = [] vlan = 0 m = re.split('\.',fwd_rule[2]) # drop rules: if fwd_rule[2] == "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) vlan = int(m[1]) else: print "ERROR: unrecognized port %s"%m[0] return -1 # vlan outputs elif fwd_rule[2].startswith('vlan'): if fwd_rule[2] in self.vlan_ports.keys(): port_list = self.vlan_ports[fwd_rule[2]] for p in port_list: out_ports.append(self.port_to_id[p]+self.PORT_TYPE_MULTIPLIER) vlan = int(fwd_rule[2][4:]) else: print "ERROR: unrecognized vlan %s"%fwd_rule[2] return -1 # physical ports - no vlan taging else: if fwd_rule[2] in self.port_to_id.keys(): out_ports.append(self.port_to_id[fwd_rule[2]] + self.PORT_TYPE_MULTIPLIER) vlan = 0 else: print "ERROR: unrecognized port %s"%fwd_rule[2] 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) print "=== Successfully Generated Transfer function ===" #print tf return 0