Fix tox errors in existing specs
[netvirt.git] / resources / tools / odltools / netvirt / flow_parser.py
1 import netvirt_utils as utils
2 import constants as const
3
4
5 OPTIONALS = ['ifname', 'lport', 'elan-tag', 'mpls', 'vpnid', 'reason',
6              'dst-mac', 'src-mac', 'ofport', 'vlanid']
7 MAC_LEN = 17
8
9 # Flow table constants
10
11 PREFIX_211_GOTO = 'Egress_Fixed_Goto_Classifier_'
12 PREFIX_211_DHCPSv4 = 'Egress_DHCP_Server_v4'
13 PREFIX_211_DHCPSv6 = 'Egress_DHCP_Server_v6_'
14 PREFIX_211_DHCPCv4 = 'Egress_DHCP_Client_v4'
15 PREFIX_211_DHCPCv6 = 'Egress_DHCP_Client_v6_'
16 PREFIX_211_ARP = 'Egress_ARP_'
17 PREFIX_211_L2BCAST = 'Egress_L2Broadcast_'
18 PREFIX_211_ICMPv6 = 'Egress_ICMPv6_'
19
20 PREFIX_213 = 'Egress_Fixed_Conntrk_'
21 PREFIX_214 = 'Egress_Fixed_Conntrk_Drop'
22 PREFIX_215 = 'Egress_Fixed_NonConntrk_Drop'
23 PREFIX_241_DHCPv4 = 'Ingress_DHCP_Server_v4'
24 PREFIX_241_DHCPv6 = 'Ingress_DHCP_Server_v6_'
25 PREFIX_241_ICMPv6 = 'Ingress_ICMPv6_'
26 PREFIX_241_ARP = 'Ingress_ARP_'
27 PREFIX_241_BCASTv4 = 'Ingress_v4_Broadcast_'
28 PREFIX_241_GOTO = 'Ingress_Fixed_Goto_Classifier_'
29 PREFIX_243 = 'Ingress_Fixed_Conntrk_'
30 PREFIX_244 = 'Ingress_Fixed_Conntrk_Drop'
31 PREFIX_245 = 'Ingress_Fixed_NonConntrk_Drop'
32
33
34 PREFIX_FOR_LPORT = {211: [PREFIX_211_GOTO, PREFIX_211_DHCPSv4,
35                           PREFIX_211_DHCPSv6, PREFIX_211_DHCPCv4,
36                           PREFIX_211_DHCPCv6, PREFIX_211_ARP,
37                           PREFIX_211_L2BCAST, PREFIX_211_ICMPv6],
38                     212: [],
39                     213: [PREFIX_213],
40                     214: [PREFIX_214],
41                     215: [PREFIX_215],
42                     241: [PREFIX_241_DHCPv4, PREFIX_241_DHCPv6,
43                           PREFIX_241_ICMPv6, PREFIX_241_ARP,
44                           PREFIX_241_BCASTv4, PREFIX_241_GOTO],
45                     242: [],
46                     243: [PREFIX_243],
47                     244: [PREFIX_244],
48                     245: [PREFIX_245]}
49
50 PREFIX_SGR_ETHER = 'ETHERnull_'
51 PREFIX_SGR_ICMP = 'ICMP_'
52 PREFIX_SGR_TCP = 'TCP_'
53 PREFIX_SGR_UDP = 'UDP_'
54 PREFIX_SGR_OTHER = 'OTHER_PROTO'
55
56 PREFIX_LPORT_SGR = {211: [], 212: [], 213: [],
57                     214: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
58                           PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
59                     215: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
60                           PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
61                     241: [], 242: [], 243: [],
62                     244: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
63                           PREFIX_SGR_UDP, PREFIX_SGR_OTHER],
64                     245: [PREFIX_SGR_ETHER, PREFIX_SGR_ICMP, PREFIX_SGR_TCP,
65                           PREFIX_SGR_UDP, PREFIX_SGR_OTHER]
66                     }
67
68 # Metadata consts
69 LPORT_MASK = 0x1fffff0000000000
70 LPORT_MASK_ZLEN = 10  # no. of trailing 0s in lport mask
71 ELAN_TAG_MASK = 0x000000ffff000000
72 ELAN_HEX_LEN = 4
73 LPORT_REG6_MASK = 0x1fffff00
74 LPORT_REG6_MASK_ZLEN = 2
75 VRFID_MASK = 0x00000000fffffffe
76
77
78 def create_flow_dict(flow_info, flow):
79     flow_dict = {}
80     flow_dict['table'] = flow['table_id']
81     flow_dict['id'] = flow['id']
82     flow_dict['name'] = flow.get('flow-name')
83     flow_dict['flow'] = flow
84     flow_dict['dpnid'] = flow_info['dpnid']
85     for opt in OPTIONALS:
86         if flow_info.get(opt):
87             flow_dict[opt] = flow_info.get(opt)
88     return flow_dict
89
90
91 def get_any_flow(flow, flow_info, groups, ifaces, ifstates, ifindexes,
92                  fibentries, vpnids, vpninterfaces, einsts, eifaces):
93     table = flow['table_id']
94     if table in const.TABLE_MAP['ifm']:
95         stale_ifm = stale_ifm_flow(flow, flow_info, ifaces, ifstates)
96         flow_info = stale_ifm if stale_ifm else get_flow_info_from_ifm_table(flow_info, flow)
97     elif table in const.TABLE_MAP['acl']:
98         stale_acl = stale_acl_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
99         flow_info = stale_acl if stale_acl else get_flow_info_from_acl_table(flow_info, flow)
100     elif table in const.TABLE_MAP['elan']:
101         stale_elan = stale_elan_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces)
102         flow_info = stale_elan if stale_elan else get_flow_info_from_elan_table(flow_info, flow)
103     elif table in const.TABLE_MAP['l3vpn']:
104         stale_l3vpn = stale_l3vpn_flow(flow, flow_info, groups, ifaces, ifindexes, vpnids, vpninterfaces, fibentries)
105         flow_info = stale_l3vpn if stale_l3vpn else get_flow_info_from_l3vpn_table(flow_info, flow)
106     else:
107         flow_info = get_flow_info_from_any(flow_info, flow)
108         iface = (get_iface_for_lport(ifaces, ifindexes, flow_info.get('lport'))
109                  if flow_info.get('lport') else None)
110         if iface and iface.get('name'):
111             flow_info['ifname'] = iface['name']
112     return create_flow_dict(flow_info, flow)
113
114
115 def stale_ifm_flow(flow, flow_info, ifaces, ifstates):
116     get_flow_info_from_ifm_table(flow_info, flow)
117     flow_ifname = flow_info['ifname']
118     iface = ifaces.get(flow_ifname)
119     if flow_ifname is not None and not iface:
120         flow_info['reason'] = 'Interface doesnt exist'
121         return create_flow_dict(flow_info, flow)
122     elif flow_ifname and ifstates.get(flow_ifname):
123         ifstate = ifstates.get(flow_ifname)
124         ncid_list = ifstate.get('lower-layer-if')
125         ncid = ncid_list[0] if ncid_list else None
126         dpn = utils.get_dpn_from_ofnodeid(ncid)
127         if dpn and dpn != flow_info['dpnid']:
128             flow_info['reason'] = 'DpnId mismatch for flow and Interface'
129             return create_flow_dict(flow_info, flow)
130         if (flow_info.get('lport') and ifstate.get('if-index')
131                 and flow_info['lport'] != ifstate['if-index']):
132             flow_info['reason'] = 'Lport and IfIndex mismatch'
133             return create_flow_dict(flow_info, flow)
134         if (flow_info.get('ofport') and ifstate.get('lower-layer-if')
135                 and flow_info['ofport'] != utils.get_ofport_from_ncid(
136                     ifstate.get('lower-layer-if')[0])):
137             flow_info['reason'] = 'OfPort mismatch'
138         if (flow_info.get('vlanid') and iface.get('odl-interface:vlan-id')
139                 and flow_info['vlanid'] != iface.get('odl-interface:vlan-id')):
140             flow_info['reason'] = 'VlanId mismatch'
141     return None
142     # return create_flow_dict(flow_info, flow)
143
144
145 def stale_l3vpn_flow(flow, flow_info, groups, ifaces, ifindexes,
146                      vpnids, vpninterfaces, fibentries):
147     get_flow_info_from_l3vpn_table(flow_info, flow)
148     lport = flow_info.get('lport')
149     iface = get_iface_for_lport(ifaces, ifindexes, lport)
150     if lport and not iface:
151         flow_info['reason'] = 'Interface for lport not found'
152         return create_flow_dict(flow_info, flow)
153     if iface:
154         flow_info['ifname'] = iface['name']
155     vpninterface = vpninterfaces.get(iface.get('name')) if iface else None
156     if not vpninterfaces:
157         flow_info['reason'] = 'VpnInterface for Lport not found'
158         return create_flow_dict(flow_info, flow)
159     vpnid = flow_info.get('vpnid')
160     if vpnid and not vpnids.get(vpnid):
161         flow_info['reason'] = 'VpnInstance for VpnId not found'
162         return create_flow_dict(flow_info, flow)
163     if vpnid and vpninterface and vpnids.get(vpnid):
164         if (vpninterface.get('vpn-instance-name') !=
165                 vpnids[vpnid]['vpn-instance-name']):
166             flow_info['reason'] = 'Lport VpnId mismatch'
167             return create_flow_dict(flow_info, flow)
168     label = flow_info.get('label')
169     fibentry = fibentries.get(label) if label else None
170     if label and not fibentry:
171         flow_info['reason'] = 'Fibentry for MplsLabel not found'
172         return create_flow_dict(flow_info, flow)
173     # Label check for group
174     prefix = fibentry.get('destPrefix') if fibentry else None
175     if prefix and flow_info.get('group-id'):
176         gid = flow_info.get('group-id')
177         if groups.get(gid) and (
178                 groups.get(gid).get('group-name', '') != prefix):
179             flow_info['reason'] = 'DestPrefix mismatch for label and group'
180             return create_flow_dict(flow_info, flow)
181     return None
182
183
184 def stale_elan_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces):
185     # hex(int(mask, 16) & int(hexa, 16))
186     get_flow_info_from_elan_table(flow_info, flow)
187     lport = flow_info.get('lport')
188     eltag = flow_info.get('elan-tag')
189     iface = get_iface_for_lport(ifaces, ifindexes, lport)
190     if lport and not iface:
191         flow_info['reason'] = 'Interface for lport not found'
192         return create_flow_dict(flow_info, flow)
193     if iface:
194         flow_info['ifname'] = iface['name']
195     if not is_elantag_valid(eltag, eifaces, einsts, iface):
196         flow_info['reason'] = 'Lport Elantag mismatch'
197         return create_flow_dict(flow_info, flow)
198     return None
199
200
201 def stale_acl_flow(flow, flow_info, ifaces, ifindexes, einsts, eifaces):
202     get_flow_info_from_acl_table(flow_info, flow)
203     lport = flow_info.get('lport')
204     eltag = flow_info.get('elan-tag')
205     iface = get_iface_for_lport(ifaces, ifindexes, lport)
206     if lport and not iface:
207             flow_info['reason'] = 'Interface for lport not found'
208             return create_flow_dict(flow_info, flow)
209     if iface:
210         flow_info['ifname'] = iface['name']
211     if not is_elantag_valid(eltag, eifaces, einsts, iface):
212         flow_info['reason'] = 'Lport Elantag mismatch'
213         return create_flow_dict(flow_info, flow)
214     #return create_flow_dict(flow_info, flow)
215     return None
216
217
218 def is_elantag_valid(eltag, eifaces, einsts, iface):
219     if (iface and eltag
220             and eltag != get_eltag_for_iface(eifaces, einsts, iface)):
221         return False
222     return True
223
224
225 def is_correct_elan_flow(flow_info, mmac, einsts, flow_host):
226     flow = flow_info.get('flow')
227     flow_etag = flow_info.get('elan-tag')
228     for k, v in mmac.iteritems():
229         mac_host = v.get('compute')
230         if einsts.get(k):
231             einst_tag = einsts.get(k).get('elan-tag')
232             #print einst_tag, flow_etag, mac_host
233             if flow_etag and einst_tag and flow_etag == einst_tag:
234                 if mac_host.startswith(flow_host):
235                     act_resubmit = get_act_resubmit(flow)
236                     if (act_resubmit and act_resubmit.get('table') == 220):
237                         return 'Correct'
238                 else:
239                     act_tunnel = get_act_set_tunnel(flow)
240                     if act_tunnel:
241                         return 'Correct'
242                 return 'Wrong'
243     return 'Wrong'
244
245
246 def get_iface_for_lport(ifaces, ifindexes, lport):
247     if lport:
248         if ifindexes.get(lport):
249             ifname = ifindexes.get(lport).get('interface-name')
250             if ifname and ifaces.get(ifname):
251                 return ifaces.get(ifname)
252     return None
253
254
255 def get_eltag_for_iface(eifaces, einsts, iface):
256     ifname = iface.get('name') if iface else None
257     eiface = eifaces.get(ifname) if ifname else None
258     einst_name = eiface.get('elan-instance-name') if eiface else None
259     einst = einsts.get(einst_name) if einst_name else None
260     return einst.get('elan-tag') if einst else None
261
262
263 # Methods to extract flow fields
264 def get_instruction_writemeta(flow):
265     for instruction in flow['instructions'].get('instruction', []):
266         if 'write-metadata' in instruction:
267             return instruction['write-metadata']
268     return None
269
270
271 def get_act_reg6load(flow):
272     for instruction in flow['instructions'].get('instruction', []):
273         if 'apply-actions' in instruction:
274             for action in instruction['apply-actions'].get('action', []):
275                 if ('openflowplugin-extension-nicira-action:nx-reg-load'
276                         in action):
277                     return action[
278                         'openflowplugin-extension-nicira-action:nx-reg-load']
279     return None
280
281
282 def get_act_conntrack(flow):
283     for instruction in flow['instructions'].get('instruction', []):
284         if 'apply-actions' in instruction:
285             for action in instruction['apply-actions'].get('action', []):
286                 if ('openflowplugin-extension-nicira-action:nx-conntrack'
287                         in action):
288                     return action[
289                         'openflowplugin-extension-nicira-action:nx-conntrack']
290
291
292 def get_act_group(flow):
293     for instruction in flow['instructions'].get('instruction', []):
294         if 'apply-actions' in instruction:
295             for action in instruction['apply-actions'].get('action', []):
296                 if 'group-action' in action:
297                     return action['group-action']
298
299
300 def get_act_set_tunnel(flow):
301     for instruction in flow['instructions'].get('instruction', []):
302         if 'apply-actions' in instruction:
303             for action in instruction['apply-actions'].get('action', []):
304                 if 'set-field' in action and 'tunnel' in action.get('set-field'):
305                     return action.get('set-field').get('tunnel')
306
307
308 def get_act_resubmit(flow):
309     for instruction in flow['instructions'].get('instruction', []):
310         if 'apply-actions' in instruction:
311             for action in instruction['apply-actions'].get('action', []):
312                 if ('openflowplugin-extension-nicira-action:nx-resubmit'
313                         in action):
314                     return action[
315                         'openflowplugin-extension-nicira-action:nx-resubmit']
316
317
318 def get_act_set_vlanid(flow):
319     for instruction in flow['instructions'].get('instruction', []):
320         if 'apply-actions' in instruction:
321             for action in instruction['apply-actions'].get('action', []):
322                 if 'set-field' in action and 'vlan-match' in action.get('set-field'):
323                     return action.get('set-field').get('vlan-match').get('vlan-id')
324
325
326 def get_act_output(flow):
327     for instruction in flow['instructions'].get('instruction', []):
328         if 'apply-actions' in instruction:
329             for action in instruction['apply-actions'].get('action', []):
330                 if 'output-action' in action and 'output-node-connector' in action.get('output-action'):
331                     return action.get('output-action')
332
333
334 def get_match_metadata(flow):
335     return flow['match'].get('metadata')
336
337
338 def get_match_reg6(flow):
339     for ofex in (
340             flow['match'].get(
341                 'openflowplugin-extension-general:extension-list', [])):
342         if (ofex['extension-key']
343                 == 'openflowplugin-extension-nicira-match:nxm-nx-reg6-key'):
344             return (
345                 ofex['extension']
346                 ['openflowplugin-extension-nicira-match:nxm-nx-reg'])
347     return None
348
349
350 def get_match_mpls(flow):
351     if flow['match'].get('protocol-match-fields'):
352         return flow['match'].get('protocol-match-fields').get('mpls-label')
353     return None
354
355
356 def get_match_tunnelid(flow):
357     if flow['match'].get('tunnel'):
358         return flow['match'].get('tunnel').get('tunnel-id')
359     return None
360
361
362 def get_match_ether_dest(flow):
363     if flow.get('match').get('ethernet-match') and flow['match'].get('ethernet-match').get('ethernet-destination'):
364         return flow['match'].get('ethernet-match').get('ethernet-destination')
365     return None
366
367
368 def get_match_ether_src(flow):
369     if flow.get('match').get('ethernet-match') and flow['match'].get('ethernet-match').get('ethernet-source'):
370         return flow['match'].get('ethernet-match').get('ethernet-source')
371     return None
372
373
374 def get_match_vlanid(flow):
375     if flow.get('match').get('vlan-match') and flow['match'].get('vlan-match').get('vlan-id'):
376         return flow['match'].get('vlan-match').get('vlan-id')
377     return None
378
379
380 def get_match_inport(flow):
381     if flow.get('match').get('in-port'):
382         return flow['match'].get('in-port')
383     return None
384
385
386 def get_flow_info_from_any(flow_info, flow):
387     w_mdata = get_instruction_writemeta(flow)
388     lport = None
389     if w_mdata:
390         metadata = w_mdata['metadata']
391         mask = w_mdata['metadata-mask']
392         if (mask & LPORT_MASK):
393             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
394             if lport:
395                 flow_info['lport'] = int(lport, 16)
396     m_metadata = get_match_metadata(flow)
397     if m_metadata:
398         metadata = m_metadata['metadata']
399         mask = m_metadata['metadata-mask']
400         if (mask & ELAN_TAG_MASK):
401             elan = ('%x' % (metadata & ELAN_TAG_MASK))[:ELAN_HEX_LEN]
402             if elan:
403                 flow_info['elan-tag'] = int(elan, 16)
404         if not lport and (mask & LPORT_MASK):
405             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
406             if lport:
407                 flow_info['lport'] = int(lport, 16)
408     m_ether_dest = get_match_ether_dest(flow)
409     if m_ether_dest and m_ether_dest.get('address'):
410         flow_info['dst-mac'] = m_ether_dest.get('address').lower()
411     m_ether_src = get_match_ether_src(flow)
412     if m_ether_src and m_ether_src.get('address'):
413         flow_info['src-mac'] = m_ether_src.get('address').lower()
414     return flow_info
415
416 # Table specific parsing
417
418 def get_ifname_from_flowid(flow_id, table):
419     splitter = ':' if table == 0 else '.'
420     # i = 2 if table == 0 else 1
421     i = 2
422     ifname = None
423     try:
424         ifname = flow_id.split(splitter)[i]
425     except IndexError:
426         tun_index = flow_id.find('tun')
427         if tun_index > -1:
428             ifname = flow_id[tun_index:]
429     return ifname
430
431
432 def get_flow_info_from_ifm_table(flow_info, flow):
433     flow_info['ifname'] = get_ifname_from_flowid(flow['id'], flow['table_id'])
434     w_mdata = get_instruction_writemeta(flow)
435     if w_mdata:
436         metadata = w_mdata['metadata']
437         mask = w_mdata['metadata-mask']
438         if (mask & LPORT_MASK):
439             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
440             flow_info['lport'] = int(lport, 16)
441     m_reg6 = get_match_reg6(flow)
442     if not flow.get('lport') and m_reg6 and m_reg6.get('value'):
443         lport = (('%x' % (m_reg6.get('value') & LPORT_REG6_MASK))
444                  [:-LPORT_REG6_MASK_ZLEN])
445         flow_info['lport'] = int(lport, 16)
446     if flow['table_id'] == 0:
447         m_inport = get_match_inport(flow)
448         if m_inport:
449             flow_info['ofport'] = utils.get_ofport_from_ncid(m_inport)
450         m_vlan = get_match_vlanid(flow)
451         if m_vlan and m_vlan.get('vlan-id'):
452             flow_info['vlanid'] = m_vlan.get('vlan-id')
453     elif flow['table_id'] == 220:
454         a_output = get_act_output(flow)
455         a_vlan = get_act_set_vlanid(flow)
456         if a_output and a_output.get('output-node-connector'):
457             flow_info['ofport'] = a_output.get('output-node-connector')
458         if a_vlan and a_vlan.get('vlan-id'):
459             flow_info['vlanid'] = a_vlan.get('vlan-id')
460     return flow_info
461
462
463 def get_flow_info_from_l3vpn_table(flow_info, flow):
464     label = get_match_mpls(flow)
465     if not label and flow['table_id'] == 36:
466         label = get_match_tunnelid(flow)
467     if label:
468         flow_info['mpls'] = label
469     a_group = get_act_group(flow)
470     if a_group and a_group.get('group-id'):
471         flow_info['group-id'] = a_group.get('group-id')
472     m_metadata = get_match_metadata(flow)
473     if m_metadata:
474         metadata = m_metadata['metadata']
475         mask = m_metadata['metadata-mask']
476         if (mask & LPORT_MASK):
477             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
478             flow_info['lport'] = int(lport, 16)
479         if (mask & VRFID_MASK):
480             flow_info['vpnid'] = (metadata & VRFID_MASK) / 2
481     return flow_info
482
483
484 def get_lport_elan_tags_from_flowid(flowid, dpnid):
485     res = flowid[:-MAC_LEN].split(dpnid)
486     lport = res[1]
487     elan = res[0][2:]
488     return lport, elan
489
490
491 def get_flow_info_from_elan_table(flow_info, flow):
492     m_metadata = get_match_metadata(flow)
493     if m_metadata:
494         metadata = m_metadata['metadata']
495         mask = m_metadata['metadata-mask']
496         if (mask & ELAN_TAG_MASK):
497             elan = ('%x' % (metadata & ELAN_TAG_MASK))[:ELAN_HEX_LEN]
498             flow_info['elan-tag'] = int(elan, 16)
499         if (mask & LPORT_MASK):
500             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
501             flow_info['lport'] = int(lport, 16)
502     m_ether_dest = get_match_ether_dest(flow)
503     if m_ether_dest and m_ether_dest.get('address'):
504         flow_info['dst-mac'] = m_ether_dest.get('address').lower()
505     m_ether_src = get_match_ether_src(flow)
506     if m_ether_src and m_ether_src.get('address'):
507         flow_info['src-mac'] = m_ether_src.get('address').lower()
508     if not flow_info.get('lport'):
509         reg6_load = get_act_reg6load(flow)
510         if reg6_load and reg6_load.get('value'):
511             # reg6load value is lport lft-shit by 8 bits.
512             lport = ('%x' % reg6_load.get('value'))[:-2]
513             flow_info['lport'] = int(lport, 16)
514     return flow_info
515
516
517 def get_flow_info_from_acl_table(flow_info, flow):
518     m_metadata = get_match_metadata(flow)
519     if m_metadata:
520         metadata = m_metadata['metadata']
521         mask = m_metadata['metadata-mask']
522         if (mask & LPORT_MASK):
523             lport = ('%x' % (metadata & LPORT_MASK))[:-LPORT_MASK_ZLEN]
524             flow_info['lport'] = int(lport, 16)
525     a_conntrk = get_act_conntrack(flow)
526     if a_conntrk and a_conntrk.get('conntrack-zone'):
527         flow_info['elan-tag'] = a_conntrk.get('conntrack-zone')
528     return flow_info
529
530
531 def get_flow_info_from_acl_table_flowid(flow_info, flow):
532     """
533         Format for ACL flow ids is as follows:
534         211:Egress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>,
535             Egress_DHCP_Server_v4<dpId>_<lportTag>__Drop_,
536             Egress_DHCP_Server_v6_<dpId>_<lportTag>__Drop_,
537             Egress_DHCP_Client_v4<dpId>_<lportTag>_<macAddress>_Permit_,
538             Egress_DHCP_Client_v6_<dpId>_<lportTag>_<macAddress>_Permit_,
539             Egress_ARP_<dpId>_<lportTag>_<allowedAddressMac><allowedAddressIp>,
540             Egress_L2Broadcast_<dpId>_<lportTag>_<attachMac>,
541             Egress_ICMPv6_<dpId>_<lportTag>_134_Drop_,
542             Egress_ICMPv6_<dpId>_<lportTag>_<icmpv6Type>_<allowedAddressMac>_Permit_,
543             Egress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>
544
545         212:Fixed_Conntrk_Classifier_<dpId>_212_<etherType>_<protocol>
546         213:Egress_Fixed_Conntrk_<dpId>_<lportTag>_<etherType>_Recirc
547         214:Fixed_Conntrk_Trk_<dpId>_Tracked_Established17,
548             Fixed_Conntrk_Trk_<dpId>_Tracked_Related17,
549             Egress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_New,
550             Egress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_Invalid,
551             ETHERnull_Egress_<lportTag>_<sgRuleId>,
552             ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
553             ICMP__Egress_<lportTag>_<sgRuleId>,
554             ICMP_V4_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
555             ICMP_V6_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
556             ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
557             ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
558             ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
559             ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
560             TCP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
561             TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
562             TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
563             TCP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
564             TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
565             TCP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
566             TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
567             TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
568             UDP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
569             UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
570             UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
571             UDP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
572             UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
573             UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
574             UDP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
575             UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
576             UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
577             OTHER_PROTO<protocolNumber>_Egress_<lportTag>_<sgRuleId>,
578             OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
579             OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
580
581         215:Egress_Fixed_NonConntrk_Drop<dpId>_<lportTag>_ACL_Rule_Miss,
582             ETHERnull_Egress_<lportTag>_<sgRuleId>,
583             ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
584             ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
585             ICMP__Egress_<lportTag>_<sgRuleId>,
586             ICMP_V4_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
587             ICMP_V6_DESTINATION_<type><code>__Egress_<lportTag>_<sgRuleId>,
588             ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
589             ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
590             ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
591             ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
592             TCP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
593             TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
594             TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
595             TCP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
596             TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
597             TCP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
598             TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
599             TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
600             UDP_DESTINATION_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
601             UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
602             UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
603             UDP_SOURCE_<port>_<portMask>_Egress_<lportTag>_<sgRuleId>,
604             UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
605             UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
606             UDP_SOURCE_ALL__Egress_<lportTag>_<sgRuleId>,
607             UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
608             UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
609             OTHER_PROTO<protocolNumber>_Egress_<lportTag>_<sgRuleId>,
610             OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>,
611             OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Egress_<lportTag>_<sgRuleId>
612
613         241:Ingress_v4_Broadcast_<dpId>_Permit,
614             Ingress_L2_Broadcast_<dpId>_Permit,
615             Ingress_DHCP_Server_v4<dpId>_<lportTag>__Permit_,
616             Ingress_DHCP_Server_v6_<dpId>_<lportTag>___Permit_,
617             Ingress_ICMPv6_<dpId>_<lportTag>_130_Permit_,
618             Ingress_ICMPv6_<dpId>_<lportTag>_134_LinkLocal_Permit_,
619             Ingress_ICMPv6_<dpId>_<lportTag>_135_Permit_,
620             Ingress_ICMPv6_<dpId>_<lportTag>_136_Permit_,
621             Ingress_ARP_<dpId>_<lportTag>,
622             Ingress_v4_Broadcast_<dpId>_<lportTag>_<broadcastAddress>_Permit,
623             Ingress_Fixed_Goto_Classifier_<dpId>_<lportTag>_<attachMac>_<attachIp>
624
625         242:Fixed_Conntrk_Classifier_<dpId>_242_<etherType>_<protocol>
626
627         243:Ingress_Fixed_Conntrk_<dpId>_<lportTag>_<etherType>_Recirc
628
629         244:Fixed_Conntrk_Trk_<dpId>_Tracked_Established220
630             Fixed_Conntrk_Trk_<dpId>_Tracked_Related220,
631             Ingress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_New,
632             Ingress_Fixed_Conntrk_Drop<dpId>_<lportTag>_Tracked_Invalid,
633             ETHERnull_Ingress_<lportTag>_<sgRuleId>,
634             ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
635             ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
636             ICMP__Ingress_<lportTag>_<sgRuleId>,
637             ICMP_V4_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
638             ICMP_V6_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
639             ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
640             ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
641             ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
642             ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
643             TCP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
644             TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
645             TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
646             TCP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
647             TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
648             TCP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
649             TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
650             TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
651             UDP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
652             UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
653             UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
654             UDP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
655             UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
656             UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
657             UDP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
658             UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
659             UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
660             OTHER_PROTO<protocolNumber>_Ingress_<lportTag>_<sgRuleId>,
661             OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
662             OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>
663
664         245:Ingress_Fixed_NonConntrk_Drop<dpId>_<lportTag>_ACL_Rule_Miss,
665             ETHERnull_Ingress_<lportTag>_<sgRuleId>,
666             ETHERnull_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
667             ETHERnull_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
668             ICMP__Ingress_<lportTag>_<sgRuleId>,
669             ICMP_V4_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
670             ICMP_V6_DESTINATION_<type><code>__Ingress_<lportTag>_<sgRuleId>,
671             ICMP__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
672             ICMP__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
673             ICMP_V4_DESTINATION_<type><code>__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
674             ICMP_V6_DESTINATION_<type><code>__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
675             TCP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
676             TCP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
677             TCP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
678             TCP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
679             TCP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
680             TCP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
681             TCP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
682             TCP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
683             UDP_DESTINATION_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
684             UDP_DESTINATION_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
685             UDP_DESTINATION_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
686             UDP_SOURCE_<port>_<portMask>_Ingress_<lportTag>_<sgRuleId>,
687             UDP_SOURCE_<port>_<portMask>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
688             UDP_SOURCE_<port>_<portMask>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
689             UDP_SOURCE_ALL__Ingress_<lportTag>_<sgRuleId>,
690             UDP_SOURCE_ALL__ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
691             UDP_SOURCE_ALL__ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
692             OTHER_PROTO<protocolNumber>_Ingress_<lportTag>_<sgRuleId>,
693             OTHER_PROTO<protocolNumber>_ipv4_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>,
694             OTHER_PROTO<protocolNumber>_ipv6_remoteACL_interface_aap_<remoteIp>_Ingress_<lportTag>_<sgRuleId>
695
696     """
697     flowid = flow['id']
698     """
699         This captures flows with following format:
700             *_<dpnid>_<lport>_*
701     """
702     for prefix in PREFIX_FOR_LPORT[flow['table_id']]:
703         if flowid.startswith(prefix):
704             res = flowid[len(prefix):].split('_')
705             try:
706                 flow_info['lport'] = int(res[1])
707                 return flow_info
708             except ValueError:
709                 """ Possible cases, ignore:
710                     241:Ingress_v4_Broadcast_<dpId>_Permit
711                 """
712                 pass
713     """
714         This captures flows with following format:
715             *_<lport>_<sgRuleId>
716     """
717     for prefix in PREFIX_LPORT_SGR[flow['table_id']]:
718         if flowid.startswith(prefix):
719             res = flowid[len(prefix):].split('_')
720             try:
721                 flow_info['lport'] = int(res[-2])
722                 return flow_info
723             except ValueError:
724                 """ Possible cases, ignore:
725                     Unexpected, log?
726                 """
727                 pass
728             except IndexError:
729                 # Unknown flow type. Log???
730                 pass
731     return flow_info