Add ovsdbmonitor GUI tool by Andy Southgate, contributed by Citrix.
[sliver-openvswitch.git] / ovsdb / ovsdbmonitor / OVEUtil.py
1 # Copyright (c) 2010 Citrix Systems, Inc.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at:
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 from OVEStandard import *
16
17 from OVEConfig import *
18
19 class OVEUtil:
20     UUID_RE = re.compile(r'([a-f0-9]{8}-[a-f0-9]{2})[a-f0-9]{2}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}')
21     
22     @classmethod
23     def paramToLongString(cls, param):
24         if isinstance(param, (types.ListType, types.TupleType)) and len(param) > 1:
25             text = str(param[1])
26         else:
27             text = str(param)
28
29         return text.replace(', ', ',\n')
30         
31     @classmethod
32     def paramToString(cls, param):
33         if isinstance(param, (types.ListType, types.TupleType)) and len(param) > 1:
34             text = str(param[1])
35         else:
36             text = str(param)
37         if OVEConfig.Inst().truncateUuids:
38             text = cls.UUID_RE.sub('\\1...', text)
39             
40         return text.replace(', ', ',\n')
41
42     @classmethod
43     def flowDecodeHeadings(self):
44         return [
45                 'Type',
46                 'Proto',
47                 'Inport',
48                 'VLAN',
49                 'Source MAC',
50                 'Destination MAC',
51                 'Source IP',
52                 'Destination IP',
53                 'Src port',
54                 'Dest port',
55                 'Packet count',
56                 'Bytes',
57                 'Used',
58                 'Tos',
59                 'PCP',
60                 'Tunnel',
61                 'Actions',
62                 ]
63
64     @classmethod
65     def getFlowColumn(cls, name):
66         lowerName = name.lower()
67         for i, columnName in enumerate(cls.flowDecodeHeadings()):
68             if lowerName == columnName.lower():
69                 return i
70         return None
71
72     ETHERTYPE_TRANS = {
73         '05ff':'ESX probe',
74         '0800':'IP',
75         '0806':'ARP',
76         '86dd':'IPv6',
77         '88cc':'LLDP'
78     }
79                   
80     ETHERPROTO_TRANS = {
81         '1':'ICMP',
82         '6':'TCP',
83         '17':'UDP'
84     }
85     
86     # Parsing of ovs-dpctl dump-flows output should be localised in this method and flowDecodeHeadings
87     @classmethod
88     def decodeFlows(cls, srcLines):
89         retVal = []
90         flowRe = re.compile(
91             # To fix this regexp:
92             #  Comment out lines, starting from the bottom, until it works, then fix the one you stopped at
93             '^' +
94             r'tunnel([^:]*):'+ # Tunnel: tunnel00000000
95             r'in_port([^:]+):' + # in_port: in_port0002
96             r'vlan([^:]+):' + #VLAN: vlan65535
97             r'([^ ]*) ' + # PCP: pcp0
98             r'mac(.{17})->' + # Source MAC: mac00:16:76:c8:1f:c9->
99             r'(.{17}) ' + # Dest MAC: mac00:16:76:c8:1f:c9
100             r'type([^ ]+) ' + #Type: type05ff
101             r'proto([^ ]+) ' + #Proto: proto0
102             r'(tos[^ ]+) ' + #Tos: tos0
103             r'ip(\d+\.\d+\.\d+\.\d+)->' + # Source IP: ip1.2.3.4->
104             r'(\d+\.\d+\.\d+\.\d+) ' + # Dest IP: 1.2.3.4
105             r'port(\d+)->' + # Source port: port0->
106             r'(\d+),\s*' + # Dest port: 0
107             r'packets:(\d*),\s*' + # Packets: packets:3423,
108             r'bytes:(\d*),\s*' + # Bytes: bytes:272024,
109             r'used:([^,]+),\s*' + # Used: used:0.870s,
110             r'actions:(\w+)\s*' + # Actions: actions:drop
111             ''
112             )
113         for line in srcLines.split('\n'):
114             if line != '':
115                 match = flowRe.match(line)
116                 if not match:
117                     OVELog("Could not decode flow record '"+line+"'.  Abandoning")
118                     return retVal
119                 else:
120                     tunnel, inport, vlan, pcp, srcmac, destmac, type, proto, tos, srcip, destip, srcport, destport, packets, bytes, used, actions = match.groups()
121                     tunnel = int(tunnel)
122                     inport = int(inport)
123                     vlan = int(vlan)
124                     type = cls.ETHERTYPE_TRANS.get(type, type)
125                     proto = cls.ETHERPROTO_TRANS.get(proto, proto)
126                     srcport = int(srcport)
127                     destport = int(destport)
128                     packets = long(packets)
129                     bytes = long(bytes)
130                     # Order below needs to match that in flowDecodeHeadings
131                     retVal.append((type, proto, inport, vlan, srcmac, destmac, srcip, destip, srcport, destport, packets, bytes, used, tos, pcp, tunnel, actions))
132                     
133         return retVal
134         
135     COLOURS = [Qt.black, Qt.darkBlue,  Qt.darkRed, Qt.darkGreen, Qt.darkMagenta, Qt.darkCyan, Qt.darkGray, Qt.darkYellow, Qt.blue, Qt.gray, Qt.magenta, Qt.red]
136         
137     @classmethod
138     def intToColour(cls, value):
139         return cls.COLOURS[value % len(cls.COLOURS)]