blob: 5e3b7dd6cc771c094c9837a161328d981889e2c9 [file] [log] [blame]
Zsolt Harasztia133a452016-12-22 01:26:57 -08001import os
2import sys
3import requests
Zsolt Harasztid036b7e2016-12-23 15:36:01 -08004from google.protobuf.json_format import MessageToDict
Zsolt Harasztia133a452016-12-22 01:26:57 -08005from termcolor import cprint, colored
6from os.path import join as pjoin
7
8
Zsolt Harasztid036b7e2016-12-23 15:36:01 -08009def pb2dict(pb_msg):
10 d = MessageToDict(pb_msg, including_default_value_fields=1,
11 preserving_proto_field_name=1)
12 return d
13
14
Zsolt Harasztia133a452016-12-22 01:26:57 -080015def p_cookie(cookie):
16 cookie = str(cookie)
17 if len(cookie) > 8:
18 return cookie[:6] + '...'
19 else:
20 return cookie
21
22'''
23 OFPP_NORMAL = 0x7ffffffa; /* Forward using non-OpenFlow pipeline. */
24 OFPP_FLOOD = 0x7ffffffb; /* Flood using non-OpenFlow pipeline. */
25 OFPP_ALL = 0x7ffffffc; /* All standard ports except input port. */
26 OFPP_CONTROLLER = 0x7ffffffd; /* Send to controller. */
27 OFPP_LOCAL = 0x7ffffffe; /* Local openflow "port". */
28 OFPP_ANY = 0x7fffffff; /* Special value used in some requests when
29'''
30
31
32def p_port(port):
33 if port & 0x7fffffff == 0x7ffffffa:
34 return 'NORMAL'
35 elif port & 0x7fffffff == 0x7ffffffb:
36 return 'FLOOD'
37 elif port & 0x7fffffff == 0x7ffffffc:
38 return 'ALL'
39 elif port & 0x7fffffff == 0x7ffffffd:
40 return 'CONTROLLER'
41 elif port & 0x7fffffff == 0x7ffffffe:
42 return 'LOCAL'
43 elif port & 0x7fffffff == 0x7fffffff:
44 return 'ANY'
45 else:
46 return str(port)
47
48
49def p_vlan_vid(vlan_vid):
50 if vlan_vid == 0:
51 return 'untagged'
52 assert vlan_vid & 4096 == 4096
53 return str(vlan_vid - 4096)
54
55
56def p_ipv4(x):
57 return '.'.join(str(v) for v in [
58 (x >> 24) & 0xff, (x >> 16) & 0xff, (x >> 8) & 0xff, x & 0xff
59 ])
60
61
62field_printers = {
63 'IN_PORT': lambda f: (100, 'in_port', p_port(f['port'])),
64 'VLAN_VID': lambda f: (101, 'vlan_vid', p_vlan_vid(f['vlan_vid'])),
65 'VLAN_PCP': lambda f: (102, 'vlan_pcp', str(f['vlan_pcp'])),
66 'ETH_TYPE': lambda f: (103, 'eth_type', '%X' % f['eth_type']),
67 'IPV4_DST': lambda f: (104, 'ipv4_dst', p_ipv4(f['ipv4_dst'])),
68 'IP_PROTO': lambda f: (105, 'ip_proto', str(f['ip_proto']))
69}
70
71
72def p_field(field):
73 assert field['oxm_class'].endswith('OPENFLOW_BASIC')
74 ofb = field['ofb_field']
75 assert not ofb['has_mask']
76 type = ofb['type'][len('OFPXMT_OFB_'):]
77 weight, field_name, value = field_printers[type](ofb)
78 return 1000 + weight, 'set_' + field_name, value
79
80
81action_printers = {
82 'SET_FIELD': lambda a: p_field(a['set_field']['field']),
83 'POP_VLAN': lambda a: (2000, 'pop_vlan', 'Yes'),
84 'PUSH_VLAN': lambda a: (2001, 'push_vlan', '%x' % a['push']['ethertype']),
85 'GROUP': lambda a: (3000, 'group', p_port(a['group']['group_id'])),
86 'OUTPUT': lambda a: (4000, 'output', p_port(a['output']['port'])),
87}
88
89
90def print_flows(what, id, type, flows, groups):
91
92 print
93 print ''.join([
94 '{} '.format(what),
95 colored(id, color='green', attrs=['bold']),
96 ' (type: ',
97 colored(type, color='blue'),
98 ')'
99 ])
100 print 'Flows ({}):'.format(len(flows))
101
102 max_field_lengths = {}
103 field_names = {}
104
105 def update_max_length(field_key, string):
106 length = len(string)
107 if length > max_field_lengths.get(field_key, 0):
108 max_field_lengths[field_key] = length
109
110 def add_field_type(field_key, field_name):
111 if field_key not in field_names:
112 field_names[field_key] = field_name
113 update_max_length(field_key, field_name)
114 else:
115 assert field_names[field_key] == field_name
116
117 cell_values = {}
118
119 # preprocess data
120 if not flows:
121 return
122 for i, flow in enumerate(flows):
123
124 def add_field(field_key, field_name, value):
125 add_field_type(field_key, field_name)
126 row = cell_values.setdefault(i, {})
127 row[field_key] = value
128 update_max_length(field_key, value)
129
130 add_field(0, 'table_id', value=str(flow['table_id']))
131 add_field(1, 'priority', value=str(flow['priority']))
132 add_field(2, 'cookie', p_cookie(flow['cookie']))
133
134 assert flow['match']['type'] == 'OFPMT_OXM'
135 for field in flow['match']['oxm_fields']:
136 assert field['oxm_class'].endswith('OPENFLOW_BASIC')
137 ofb = field['ofb_field']
138 assert not ofb['has_mask'], 'masked match not handled yet' # TODO
139 type = ofb['type'][len('OFPXMT_OFB_'):]
140 add_field(*field_printers[type](ofb))
141
142 for instruction in flow['instructions']:
143 if instruction['type'] == 4:
144 for action in instruction['actions']['actions']:
145 type = action['type'][len('OFPAT_'):]
146 add_field(*action_printers[type](action))
147
148 # print header
149 field_keys = sorted(field_names.keys())
150 def p_sep():
151 print '+' + '+'.join(
152 [(max_field_lengths[k] + 2) * '-' for k in field_keys]) + '+'
153
154 p_sep()
155 print '| ' + ' | '.join(
156 '%%%ds' % max_field_lengths[k] % field_names[k]
157 for k in field_keys) + ' |'
158 p_sep()
159
160 # print values
161 for i in xrange(len(flows)):
162 row = cell_values[i]
163 cprint('| ' + ' | '.join(
164 '%%%ds' % max_field_lengths[k] % row.get(k, '')
165 for k in field_keys
166 ) + ' |')
167 if not ((i + 1) % 3):
168 p_sep()
169
170 if ((i + 1) % 3):
171 p_sep()
172
173 # TODO groups TBF
174 assert len(groups) == 0
175
176