Dan Talayco | f75360a | 2010-02-05 22:22:54 -0800 | [diff] [blame] | 1 | """This module parses OpenFlow packets. |
| 2 | |
| 3 | Unfortunately, this has to be updated manually for each OpenFlow version |
| 4 | and packet type. Ugly. |
| 5 | |
| 6 | (C) Copyright Stanford University |
| 7 | Date October 2009 |
| 8 | Created by ykk |
| 9 | """ |
| 10 | class parser: |
| 11 | """Parser for OpenFlow packets |
| 12 | |
| 13 | (C) Copyright Stanford University |
| 14 | Date October 2009 |
| 15 | Created by ykk |
| 16 | """ |
| 17 | def __init__(self, messages): |
| 18 | """Initialize |
| 19 | """ |
| 20 | ##Internal reference to OpenFlow messages |
| 21 | self.__messages = messages |
| 22 | |
| 23 | def describe(self, packet): |
| 24 | """Parse OpenFlow packet and return string description |
| 25 | """ |
| 26 | dic = self.__messages.peek_from_front("ofp_header", packet) |
| 27 | desc = self.header_describe(dic) |
| 28 | if (dic["type"][0] == self.__messages.get_value("OFPT_HELLO")): |
| 29 | pass |
| 30 | elif (dic["type"][0] == self.__messages.get_value("OFPT_SET_CONFIG")): |
| 31 | desc += "\n\t"+self.switch_config_describe(packet) |
| 32 | elif (dic["type"][0] == self.__messages.get_value("OFPT_FLOW_MOD")): |
| 33 | (fmdic, remaining) = self.__messages.unpack_from_front("ofp_flow_mod", packet) |
| 34 | desc += self.flow_mod_describe(fmdic, "\n\t") |
| 35 | desc += "\n\twith remaining "+str(len(remaining))+" bytes" |
| 36 | else: |
| 37 | desc += "\n\tUnparsed..." |
| 38 | return desc |
| 39 | |
| 40 | def flow_mod_describe(self, packet, prefix=""): |
| 41 | """Parse flow mod and return description |
| 42 | """ |
| 43 | dic = self.__assert_dic(packet, "ofp_flow_mod") |
| 44 | if (dic == None): |
| 45 | return "" |
| 46 | return prefix+\ |
| 47 | "Flow_mod of command "+self.__messages.get_enum_name("ofp_flow_mod_command", dic["command"][0])+\ |
| 48 | " idle/hard timeout:"+str(dic["idle_timeout"][0])+"/"+str(dic["hard_timeout"][0])+\ |
| 49 | self.match_describe(dic, "match.", "\n\t")+\ |
| 50 | prefix+\ |
| 51 | "(priority:"+str(dic["priority"][0])+\ |
| 52 | "/buffer id:"+str(dic["buffer_id"][0])+\ |
| 53 | "/out port:"+str(dic["out_port"][0])+")" |
| 54 | |
| 55 | def match_describe(self, dic, nameprefix="", prefix=""): |
| 56 | """Return description for ofp match |
| 57 | """ |
| 58 | return prefix+"match wildcards:%x" % dic[nameprefix+"wildcards"][0]+\ |
| 59 | " inport="+str(dic[nameprefix+"in_port"][0])+\ |
| 60 | prefix+" "+\ |
Rich Lane | d0478ff | 2013-03-11 12:46:58 -0700 | [diff] [blame] | 61 | " ethertype="+str(dic[nameprefix+"eth_type"][0])+\ |
| 62 | " vlan="+str(dic[nameprefix+"vlan_vid"][0])+\ |
| 63 | " "+self.eth_describe(dic[nameprefix+"eth_src"])+"->"+\ |
| 64 | self.eth_describe(dic[nameprefix+"eth_dst"])+\ |
Dan Talayco | f75360a | 2010-02-05 22:22:54 -0800 | [diff] [blame] | 65 | prefix+" "+\ |
Rich Lane | d0478ff | 2013-03-11 12:46:58 -0700 | [diff] [blame] | 66 | " ipproto="+str(dic[nameprefix+"ip_proto"][0])+\ |
| 67 | " "+self.ip_describe(dic[nameprefix+"ipv4_src"][0])+\ |
| 68 | "->"+self.ip_describe(dic[nameprefix+"ipv4_src"][0])+\ |
Dan Talayco | f75360a | 2010-02-05 22:22:54 -0800 | [diff] [blame] | 69 | prefix+" "+\ |
Rich Lane | d0478ff | 2013-03-11 12:46:58 -0700 | [diff] [blame] | 70 | " transport "+str(dic[nameprefix+"tcp_src"][0])+\ |
| 71 | "->"+str(dic[nameprefix+"tcp_dst"][0]) |
Dan Talayco | f75360a | 2010-02-05 22:22:54 -0800 | [diff] [blame] | 72 | |
| 73 | def switch_config_describe(self, packet): |
| 74 | """Parse OpenFlow switch config and return description |
| 75 | """ |
| 76 | dic = self.__assert_dic(packet, "ofp_switch_config") |
| 77 | if (dic == None): |
| 78 | return "" |
| 79 | return "with flag "+str(self.__messages.get_enum_name("ofp_config_flags", dic["flags"][0]))+\ |
| 80 | " and miss send length "+str(dic["miss_send_len"][0]) |
| 81 | |
| 82 | def header_describe(self, packet): |
| 83 | """Parse OpenFlow header and return string description |
| 84 | """ |
| 85 | dic = self.__assert_dic(packet, "ofp_header") |
| 86 | if (dic == None): |
| 87 | return "" |
| 88 | return self.__messages.get_enum_name("ofp_type", dic["type"][0])+" packet "+\ |
| 89 | "(length:"+str(dic["length"][0])+\ |
| 90 | "/xid:"+str(dic["xid"][0])+")" |
| 91 | |
| 92 | def ip_describe(self, value): |
| 93 | """Return string for ip address |
| 94 | """ |
| 95 | desc = "" |
| 96 | for i in range(0,4): |
| 97 | (value, cv) = divmod(value, 256) |
| 98 | desc = str(cv).strip() +"." + desc |
| 99 | return desc |
| 100 | |
| 101 | def eth_describe(self, etheraddr): |
| 102 | """Return string for ethernet address |
| 103 | """ |
| 104 | desc = "" |
| 105 | for value in etheraddr: |
| 106 | desc += ":"+("%x" % value).zfill(2) |
| 107 | return desc[1:] |
| 108 | |
| 109 | def __assert_dic(self, packet, typename): |
| 110 | """Assert and ensure dictionary is given |
| 111 | """ |
| 112 | dic = None |
| 113 | if (isinstance(packet, str)): |
| 114 | dic = self.__messages.peek_from_front(typename, packet) |
| 115 | elif (isinstance(packet, dict)): |
| 116 | dic = packet |
| 117 | return dic |