6 from collections import defaultdict
8 help ='''## readable_flows.py:
10 This script pretty prints ovs flows created by ovsdb. Features include:
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
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
24 if len(sys.argv) > 1 and sys.argv[1] in ['-h', '-?', '--h', '--help']:
32 20: 'GATEWAY_RESOLVER',\
46 PORT_LIST_CMD = 'neutron port-list -c mac_address -c fixed_ips'.split(' ')
48 LINE_PATTERN = '.*(?P<table>table=\d*), (?P<counters>n_packets=\d*, n_bytes=\d*), (?P<prio>priority=\d*)?,?(?P<rule>.*)'
51 def print_rules(table, rules_by_prio):
54 print table.upper() + ' (' + TABLE_NAME[int(table[cut+1:])] + ')'
56 prios = rules_by_prio.keys()
60 print ' priority=%i' % prio,
61 if DEFAULT_PRIO == prio: print '(DEFAULT_PRIO)'
63 for rule in rules_by_prio[prio]:
64 print_flow(' ', re.sub('actions=', 'ACTIONS=', rule))
66 def tun_match_to_decimal(m):
68 return 'tun_id=0x%s(%i)' % (s, int(s, 16))
69 def tun_set_to_decimal(m):
71 return '0x%s(%i)->tun_id' % (s, int(s, 16))
73 def print_flow(indent, f):
77 # if len(flow) <= MAX_LINE:
81 # cut = flow.find('ACTIONS')
82 # match = flow[0:cut - 1]
83 # action = indent + indent + flow[cut:]
86 # if len(action) <= MAX_LINE:
89 # cut = action.rfind(',', 0, MAX_LINE)
93 # print action[0:cut + 1]
94 # action = indent + indent + (' ' * len('ACTIONS=')) + action[cut +1:]
96 port_list_out = subprocess.check_output(PORT_LIST_CMD)
99 for line in port_list_out.split('\n')[2:]:
100 if re.match('^$', line): continue
101 if '----' in line: continue
102 line = re.sub('^\| ', '', line)
103 line = re.sub(' *\|$', '', line)
104 (mac, fixed_ip) = line.split(' | ')
105 ip = eval(fixed_ip)['ip_address']
106 addresses.append((mac, ip))
109 rules_by_prio = defaultdict(list)
110 for line in sys.stdin:
111 for (mac, ip) in addresses:
112 line = re.sub(mac, '%s(%s)' % (mac, ip), line)
113 line = re.sub('=%s(\D)' % ip, '=%s(%s)\\1' % (ip, mac), line)
114 line = re.sub('tun_id=0x(?P<num>[0-9a-fA-F]*)', tun_match_to_decimal, line)
115 line = re.sub('0x(?P<num>[0-9a-fA-F]*)->tun_id', tun_set_to_decimal, line)
116 match = re.match(LINE_PATTERN, line)
118 print '[Not a flow line?]: ' + line,
121 if match.group('table') != table:
123 print_rules(table, rules_by_prio)
124 rules_by_prio = defaultdict(list)
125 table = match.group('table')
128 prio_str = match.group('prio')
129 if None != prio_str: prio = int(prio_str[9:])
130 rules_by_prio[prio].append(match.group('rule'))
132 print_rules(table, rules_by_prio)