Freeze upstream versions
[netvirt.git] / resources / commons / readable_flows.py
1 #!/usr/bin/python
2
3 import subprocess
4 import sys
5 import re
6 from collections import defaultdict
7
8 help ='''## readable_flows.py:
9
10 This script pretty prints ovs flows created by ovsdb. Features include:
11
12 1. Where possible, MACs are followed by their corresponding IP (in parenthases) and vice-versa
13 2. Tunnel ids are followed by the decimal representation used by Open Daylight
14 3. Counters and stats are removed so that meaningful diffs may be generated
15 4. Table numbers are given together with descriptive names
16 5. Flows are grouped together by priority in decending order
17
18 ### Usage:
19 This script must be run on the OpenStack controller since it uses the
20 neutron command to map MACs and IPs.
21 > sudo ovs-ofctl -OOpenFlow13 dump-flows br-int | python readable_flows.py
22 '''
23
24 if len(sys.argv) > 1 and sys.argv[1] in ['-h', '-?', '--h', '--help']:
25     print help
26     sys.exit(0)
27
28 DEFAULT_PRIO=32768
29
30 TABLE_NAME = { \
31 0: 'CLASSIFIER',\
32 20: 'GATEWAY_RESOLVER',\
33 10: 'DIRECTOR',\
34 10: 'SFC_CLASSIFIER',\
35 20: 'ARP_RESPONDER',\
36 30: 'INBOUND_NAT',\
37 40: 'EGRESS_ACL',\
38 50: 'LOAD_BALANCER',\
39 60: 'ROUTING',\
40 70: 'ICMP_ECHO',\
41 70: 'L3_FORWARDING',\
42 80: 'L2_REWRITE',\
43 90: 'INGRESS_ACL',\
44 100: 'OUTBOUND_NAT',\
45 110: 'L2_FORWARDING'}
46
47 PORT_LIST_CMD = 'neutron port-list -c mac_address -c fixed_ips'.split(' ')
48
49 LINE_PATTERN = '.*(?P<table>table=\d*), (?P<counters>n_packets=\d*, n_bytes=\d*), (?P<prio>priority=\d*)?,?(?P<rule>.*)'
50 MAX_LINE = 30
51
52 def print_rules(table, rules_by_prio):
53     print ''
54     cut = table.find('=')
55     print table.upper() + ' (' + TABLE_NAME[int(table[cut+1:])] + ')'
56
57     prios = rules_by_prio.keys()
58     prios.sort()
59     prios.reverse()
60     for prio in prios:
61         print '    priority=%i' % prio,
62         if DEFAULT_PRIO == prio: print '(DEFAULT_PRIO)'
63         else: print ''
64         for rule in rules_by_prio[prio]:
65             print_flow('        ', re.sub('actions=', 'ACTIONS=', rule))
66
67 def tun_match_to_decimal(m):
68     s = m.group('num')
69     return 'tun_id=0x%s(%i)' % (s, int(s, 16))
70 def tun_set_to_decimal(m):
71     s = m.group('num')
72     return '0x%s(%i)->tun_id' % (s, int(s, 16))
73
74 def print_flow(indent, f):
75     print indent + f
76 # WIP
77 #    flow = indent + f
78 #    if len(flow) <= MAX_LINE: 
79 #        print flow
80 #        return
81 #    
82 #    cut = flow.find('ACTIONS')
83 #    match = flow[0:cut - 1]
84 #    action = indent + indent + flow[cut:]
85 #    print match
86 #    while action:
87 #        if len(action) <= MAX_LINE:
88 #            print action
89 #            break
90 #        cut = action.rfind(',', 0, MAX_LINE)
91 #        if cut < 2: 
92 #            print action
93 #            break
94 #        print action[0:cut + 1]
95 #        action = indent + indent + (' ' * len('ACTIONS=')) + action[cut +1:]
96
97 port_list_out = subprocess.check_output(PORT_LIST_CMD)
98
99 addresses = []
100 for line in port_list_out.split('\n')[2:]:
101     if re.match('^$', line): continue
102     if '----' in line: continue
103     line = re.sub('^\| ', '', line)
104     line = re.sub(' *\|$', '', line)
105     (mac, fixed_ip) = line.split(' | ')
106     ip = eval(fixed_ip)['ip_address']
107     addresses.append((mac, ip))
108
109 table = ''
110 rules_by_prio = defaultdict(list)
111 for line in sys.stdin:
112     for (mac, ip) in addresses: 
113         line = re.sub(mac, '%s(%s)' % (mac, ip), line)
114         line = re.sub('=%s(\D)' % ip, '=%s(%s)\\1' % (ip, mac), line)
115     line = re.sub('tun_id=0x(?P<num>[0-9a-fA-F]*)', tun_match_to_decimal, line)
116     line = re.sub('0x(?P<num>[0-9a-fA-F]*)->tun_id', tun_set_to_decimal, line)
117     match = re.match(LINE_PATTERN, line)
118     if not match: 
119         print '[Not a flow line?]:  ' + line,
120         continue
121
122     if  match.group('table') != table:
123         if table:
124             print_rules(table, rules_by_prio)
125             rules_by_prio = defaultdict(list)
126         table = match.group('table')
127
128     prio = DEFAULT_PRIO
129     prio_str = match.group('prio')
130     if None != prio_str: prio = int(prio_str[9:])
131     rules_by_prio[prio].append(match.group('rule'))
132
133 print_rules(table, rules_by_prio)
134