Se reinstalo ryu para configurar STP y que el restAPI no sea publico(127.0.0.1)
[vsorcdistro/.git] / ryu / ryu / lib / ofctl_v1_5.py
1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
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
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 import base64
17 import logging
18
19 from ryu.ofproto import ether
20 from ryu.ofproto import ofproto_v1_5
21 from ryu.ofproto import ofproto_v1_5_parser
22 from ryu.lib import ofctl_utils
23
24 LOG = logging.getLogger(__name__)
25
26 DEFAULT_TIMEOUT = 1.0
27
28 UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_5)
29 str_to_int = ofctl_utils.str_to_int
30
31
32 def to_action(dp, dic):
33     ofp = dp.ofproto
34     parser = dp.ofproto_parser
35     action_type = dic.get('type')
36     return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL)
37
38
39 def _get_actions(dp, dics):
40     actions = []
41     for d in dics:
42         action = to_action(dp, d)
43         if action is not None:
44             actions.append(action)
45         else:
46             LOG.error('Unknown action type: %s', d)
47     return actions
48
49
50 def to_instructions(dp, insts):
51     instructions = []
52     ofp = dp.ofproto
53     parser = dp.ofproto_parser
54
55     for i in insts:
56         inst_type = i.get('type')
57         if inst_type in ['APPLY_ACTIONS', 'WRITE_ACTIONS']:
58             dics = i.get('actions', [])
59             actions = _get_actions(dp, dics)
60             if actions:
61                 if inst_type == 'APPLY_ACTIONS':
62                     instructions.append(
63                         parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
64                                                      actions))
65                 else:
66                     instructions.append(
67                         parser.OFPInstructionActions(ofp.OFPIT_WRITE_ACTIONS,
68                                                      actions))
69         elif inst_type == 'CLEAR_ACTIONS':
70             instructions.append(
71                 parser.OFPInstructionActions(ofp.OFPIT_CLEAR_ACTIONS, []))
72         elif inst_type == 'GOTO_TABLE':
73             table_id = str_to_int(i.get('table_id'))
74             instructions.append(parser.OFPInstructionGotoTable(table_id))
75         elif inst_type == 'WRITE_METADATA':
76             metadata = str_to_int(i.get('metadata'))
77             metadata_mask = (str_to_int(i['metadata_mask'])
78                              if 'metadata_mask' in i
79                              else parser.UINT64_MAX)
80             instructions.append(
81                 parser.OFPInstructionWriteMetadata(
82                     metadata, metadata_mask))
83         else:
84             LOG.error('Unknown instruction type: %s', inst_type)
85
86     return instructions
87
88
89 def action_to_str(act):
90     s = act.to_jsondict()[act.__class__.__name__]
91     t = UTIL.ofp_action_type_to_user(s['type'])
92     s['type'] = t if t != s['type'] else 'UNKNOWN'
93
94     if t == 'SET_FIELD':
95         field = s.pop('field')
96         s['field'] = field['OXMTlv']['field']
97         s['mask'] = field['OXMTlv']['mask']
98         s['value'] = field['OXMTlv']['value']
99     elif t == 'COPY_FIELD':
100         oxm_ids = s.pop('oxm_ids')
101         s['src_oxm_id'] = oxm_ids[0]['OFPOxmId']['type']
102         s['dst_oxm_id'] = oxm_ids[1]['OFPOxmId']['type']
103
104     return s
105
106
107 def instructions_to_str(instructions):
108
109     s = []
110
111     for i in instructions:
112         v = i.to_jsondict()[i.__class__.__name__]
113         t = UTIL.ofp_instruction_type_to_user(v['type'])
114         inst_type = t if t != v['type'] else 'UNKNOWN'
115         # apply/write/clear-action instruction
116         if isinstance(i, ofproto_v1_5_parser.OFPInstructionActions):
117             acts = []
118             for a in i.actions:
119                 acts.append(action_to_str(a))
120             v['type'] = inst_type
121             v['actions'] = acts
122             s.append(v)
123         # others
124         else:
125             v['type'] = inst_type
126             s.append(v)
127
128     return s
129
130
131 def to_match(dp, attrs):
132     convert = {'in_port': UTIL.ofp_port_from_user,
133                'in_phy_port': str_to_int,
134                'metadata': ofctl_utils.to_match_masked_int,
135                'eth_dst': ofctl_utils.to_match_eth,
136                'eth_src': ofctl_utils.to_match_eth,
137                'eth_type': str_to_int,
138                'vlan_vid': to_match_vid,
139                'vlan_pcp': str_to_int,
140                'ip_dscp': str_to_int,
141                'ip_ecn': str_to_int,
142                'ip_proto': str_to_int,
143                'ipv4_src': ofctl_utils.to_match_ip,
144                'ipv4_dst': ofctl_utils.to_match_ip,
145                'tcp_src': str_to_int,
146                'tcp_dst': str_to_int,
147                'udp_src': str_to_int,
148                'udp_dst': str_to_int,
149                'sctp_src': str_to_int,
150                'sctp_dst': str_to_int,
151                'icmpv4_type': str_to_int,
152                'icmpv4_code': str_to_int,
153                'arp_op': str_to_int,
154                'arp_spa': ofctl_utils.to_match_ip,
155                'arp_tpa': ofctl_utils.to_match_ip,
156                'arp_sha': ofctl_utils.to_match_eth,
157                'arp_tha': ofctl_utils.to_match_eth,
158                'ipv6_src': ofctl_utils.to_match_ip,
159                'ipv6_dst': ofctl_utils.to_match_ip,
160                'ipv6_flabel': str_to_int,
161                'icmpv6_type': str_to_int,
162                'icmpv6_code': str_to_int,
163                'ipv6_nd_target': ofctl_utils.to_match_ip,
164                'ipv6_nd_sll': ofctl_utils.to_match_eth,
165                'ipv6_nd_tll': ofctl_utils.to_match_eth,
166                'mpls_label': str_to_int,
167                'mpls_tc': str_to_int,
168                'mpls_bos': str_to_int,
169                'pbb_isid': ofctl_utils.to_match_masked_int,
170                'tunnel_id': ofctl_utils.to_match_masked_int,
171                'ipv6_exthdr': ofctl_utils.to_match_masked_int,
172                'pbb_uca': str_to_int,
173                'tcp_flags': str_to_int,
174                'actset_output': str_to_int,
175                'packet_type': ofctl_utils.to_match_packet_type}
176
177     keys = {'dl_dst': 'eth_dst',
178             'dl_src': 'eth_src',
179             'dl_type': 'eth_type',
180             'dl_vlan': 'vlan_vid',
181             'nw_src': 'ipv4_src',
182             'nw_dst': 'ipv4_dst',
183             'nw_proto': 'ip_proto'}
184
185     if attrs.get('eth_type') == ether.ETH_TYPE_ARP:
186         if 'ipv4_src' in attrs and 'arp_spa' not in attrs:
187             attrs['arp_spa'] = attrs['ipv4_src']
188             del attrs['ipv4_src']
189         if 'ipv4_dst' in attrs and 'arp_tpa' not in attrs:
190             attrs['arp_tpa'] = attrs['ipv4_dst']
191             del attrs['ipv4_dst']
192
193     kwargs = {}
194     for key, value in attrs.items():
195         if key in keys:
196             # For old field name
197             key = keys[key]
198         if key in convert:
199             value = convert[key](value)
200             kwargs[key] = value
201         else:
202             LOG.error('Unknown match field: %s', key)
203
204     return dp.ofproto_parser.OFPMatch(**kwargs)
205
206
207 def to_match_vid(value):
208     return ofctl_utils.to_match_vid(value, ofproto_v1_5.OFPVID_PRESENT)
209
210
211 def match_to_str(ofmatch):
212     match = {}
213
214     ofmatch = ofmatch.to_jsondict()['OFPMatch']
215     ofmatch = ofmatch['oxm_fields']
216
217     for match_field in ofmatch:
218         key = match_field['OXMTlv']['field']
219         mask = match_field['OXMTlv']['mask']
220         value = match_field['OXMTlv']['value']
221         if key == 'vlan_vid':
222             value = match_vid_to_str(value, mask)
223         elif key == 'in_port':
224             value = UTIL.ofp_port_to_user(value)
225         elif key == 'packet_type':
226             value = [value >> 16, value & 0xffff]
227         else:
228             if mask is not None:
229                 value = str(value) + '/' + str(mask)
230         match.setdefault(key, value)
231
232     return match
233
234
235 def match_vid_to_str(value, mask):
236     return ofctl_utils.match_vid_to_str(
237         value, mask, ofproto_v1_5.OFPVID_PRESENT)
238
239
240 def wrap_dpid_dict(dp, value, to_user=True):
241     if to_user:
242         return {str(dp.id): value}
243
244     return {dp.id: value}
245
246
247 def stats_to_str(ofstats):
248
249     stats = {}
250     ofstats = ofstats.to_jsondict()['OFPStats']
251     ofstats = ofstats['oxs_fields']
252
253     for s in ofstats:
254         key = s['OXSTlv']['field']
255         if key == 'duration':
256             value = {
257                 'duration_sec': s['OXSTlv']['value'][0],
258                 'duration_nsec': s['OXSTlv']['value'][1],
259             }
260         elif key == 'idle_time':
261             value = {
262                 'idle_time_sec': s['OXSTlv']['value'][0],
263                 'idle_time_nsec': s['OXSTlv']['value'][1],
264             }
265         else:
266             value = s['OXSTlv']['value']
267         stats.setdefault(key, value)
268
269     return stats
270
271
272 def get_desc_stats(dp, waiters, to_user=True):
273     stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0)
274     msgs = []
275     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
276     s = {}
277
278     for msg in msgs:
279         stats = msg.body
280         s = stats.to_jsondict()[stats.__class__.__name__]
281
282     return wrap_dpid_dict(dp, s, to_user)
283
284
285 def get_queue_stats(dp, waiters, port_no=None, queue_id=None, to_user=True):
286     if port_no is None:
287         port_no = dp.ofproto.OFPP_ANY
288     else:
289         port_no = UTIL.ofp_port_from_user(port_no)
290     if queue_id is None:
291         queue_id = dp.ofproto.OFPQ_ALL
292     else:
293         queue_id = UTIL.ofp_queue_from_user(queue_id)
294
295     stats = dp.ofproto_parser.OFPQueueStatsRequest(
296         dp, 0, port_no, queue_id)
297     msgs = []
298     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
299
300     desc = []
301     for msg in msgs:
302         stats = msg.body
303         for stat in stats:
304             s = stat.to_jsondict()[stat.__class__.__name__]
305             properties = []
306             for prop in stat.properties:
307                 p = prop.to_jsondict()[prop.__class__.__name__]
308                 if to_user:
309                     t = UTIL.ofp_queue_stats_prop_type_to_user(prop.type)
310                     p['type'] = t if t != p['type'] else 'UNKNOWN'
311                 properties.append(p)
312             s['properties'] = properties
313             desc.append(s)
314
315     return wrap_dpid_dict(dp, desc, to_user)
316
317
318 def get_queue_desc(dp, waiters, port_no=None, queue_id=None, to_user=True):
319     if port_no is None:
320         port_no = dp.ofproto.OFPP_ANY
321     else:
322         port_no = UTIL.ofp_port_from_user(port_no)
323     if queue_id is None:
324         queue_id = dp.ofproto.OFPQ_ALL
325     else:
326         queue_id = UTIL.ofp_queue_from_user(queue_id)
327
328     stats = dp.ofproto_parser.OFPQueueDescStatsRequest(
329         dp, 0, port_no, queue_id)
330     msgs = []
331     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
332
333     configs = []
334     for msg in msgs:
335         for queue in msg.body:
336             q = queue.to_jsondict()[queue.__class__.__name__]
337             prop_list = []
338             for prop in queue.properties:
339                 p = prop.to_jsondict()[prop.__class__.__name__]
340                 if to_user:
341                     t = UTIL.ofp_queue_desc_prop_type_to_user(prop.type)
342                     p['type'] = t if t != prop.type else 'UNKNOWN'
343                 prop_list.append(p)
344             q['properties'] = prop_list
345             configs.append(q)
346
347     return wrap_dpid_dict(dp, configs, to_user)
348
349
350 def get_flow_desc_stats(dp, waiters, flow=None, to_user=True):
351     flow = flow if flow else {}
352     table_id = UTIL.ofp_table_from_user(
353         flow.get('table_id', dp.ofproto.OFPTT_ALL))
354     flags = str_to_int(flow.get('flags', 0))
355     out_port = UTIL.ofp_port_from_user(
356         flow.get('out_port', dp.ofproto.OFPP_ANY))
357     out_group = UTIL.ofp_group_from_user(
358         flow.get('out_group', dp.ofproto.OFPG_ANY))
359     cookie = str_to_int(flow.get('cookie', 0))
360     cookie_mask = str_to_int(flow.get('cookie_mask', 0))
361     match = to_match(dp, flow.get('match', {}))
362     # Note: OpenFlow does not allow to filter flow entries by priority,
363     # but for efficiency, ofctl provides the way to do it.
364     priority = str_to_int(flow.get('priority', -1))
365
366     stats = dp.ofproto_parser.OFPFlowDescStatsRequest(
367         dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
368         match)
369
370     msgs = []
371     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
372
373     flows = []
374     for msg in msgs:
375         for stats in msg.body:
376             if 0 <= priority != stats.priority:
377                 continue
378
379             s = stats.to_jsondict()[stats.__class__.__name__]
380             s['instructions'] = instructions_to_str(stats.instructions)
381             s['stats'] = stats_to_str(stats.stats)
382             s['match'] = match_to_str(stats.match)
383             flows.append(s)
384
385     return wrap_dpid_dict(dp, flows, to_user)
386
387
388 def get_flow_stats(dp, waiters, flow=None, to_user=True):
389     flow = flow if flow else {}
390     table_id = UTIL.ofp_table_from_user(
391         flow.get('table_id', dp.ofproto.OFPTT_ALL))
392     flags = str_to_int(flow.get('flags', 0))
393     out_port = UTIL.ofp_port_from_user(
394         flow.get('out_port', dp.ofproto.OFPP_ANY))
395     out_group = UTIL.ofp_group_from_user(
396         flow.get('out_group', dp.ofproto.OFPG_ANY))
397     cookie = str_to_int(flow.get('cookie', 0))
398     cookie_mask = str_to_int(flow.get('cookie_mask', 0))
399     match = to_match(dp, flow.get('match', {}))
400     # Note: OpenFlow does not allow to filter flow entries by priority,
401     # but for efficiency, ofctl provides the way to do it.
402     priority = str_to_int(flow.get('priority', -1))
403
404     stats = dp.ofproto_parser.OFPFlowStatsRequest(
405         dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
406         match)
407
408     msgs = []
409     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
410
411     flows = []
412     for msg in msgs:
413         for stats in msg.body:
414             if 0 <= priority != stats.priority:
415                 continue
416
417             s = stats.to_jsondict()[stats.__class__.__name__]
418             s['stats'] = stats_to_str(stats.stats)
419             s['match'] = match_to_str(stats.match)
420             flows.append(s)
421
422     return wrap_dpid_dict(dp, flows, to_user)
423
424
425 def get_aggregate_flow_stats(dp, waiters, flow=None, to_user=True):
426     flow = flow if flow else {}
427     table_id = UTIL.ofp_table_from_user(
428         flow.get('table_id', dp.ofproto.OFPTT_ALL))
429     flags = str_to_int(flow.get('flags', 0))
430     out_port = UTIL.ofp_port_from_user(
431         flow.get('out_port', dp.ofproto.OFPP_ANY))
432     out_group = UTIL.ofp_group_from_user(
433         flow.get('out_group', dp.ofproto.OFPG_ANY))
434     cookie = str_to_int(flow.get('cookie', 0))
435     cookie_mask = str_to_int(flow.get('cookie_mask', 0))
436     match = to_match(dp, flow.get('match', {}))
437
438     stats = dp.ofproto_parser.OFPAggregateStatsRequest(
439         dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
440         match)
441
442     msgs = []
443     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
444
445     flows = []
446     for msg in msgs:
447         stats = msg.body
448         s = stats.to_jsondict()[stats.__class__.__name__]
449         s['stats'] = stats_to_str(stats.stats)
450         flows.append(s)
451
452     return wrap_dpid_dict(dp, flows, to_user)
453
454
455 def get_table_stats(dp, waiters, to_user=True):
456     stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0)
457     msgs = []
458     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
459
460     tables = []
461     for msg in msgs:
462         stats = msg.body
463         for stat in stats:
464             s = stat.to_jsondict()[stat.__class__.__name__]
465
466             if to_user:
467                 s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
468
469             tables.append(s)
470
471     return wrap_dpid_dict(dp, tables, to_user)
472
473
474 def get_table_features(dp, waiters, to_user=True):
475     stats = dp.ofproto_parser.OFPTableFeaturesStatsRequest(dp, 0, [])
476     msgs = []
477     ofproto = dp.ofproto
478     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
479
480     p_type_instructions = [ofproto.OFPTFPT_INSTRUCTIONS,
481                            ofproto.OFPTFPT_INSTRUCTIONS_MISS]
482
483     p_type_next_tables = [ofproto.OFPTFPT_NEXT_TABLES,
484                           ofproto.OFPTFPT_NEXT_TABLES_MISS,
485                           ofproto.OFPTFPT_TABLE_SYNC_FROM]
486
487     p_type_actions = [ofproto.OFPTFPT_WRITE_ACTIONS,
488                       ofproto.OFPTFPT_WRITE_ACTIONS_MISS,
489                       ofproto.OFPTFPT_APPLY_ACTIONS,
490                       ofproto.OFPTFPT_APPLY_ACTIONS_MISS]
491
492     p_type_packet = ofproto.OFPTFPT_PACKET_TYPES
493
494     p_type_oxms = [ofproto.OFPTFPT_MATCH,
495                    ofproto.OFPTFPT_WILDCARDS,
496                    ofproto.OFPTFPT_WRITE_SETFIELD,
497                    ofproto.OFPTFPT_WRITE_SETFIELD_MISS,
498                    ofproto.OFPTFPT_APPLY_SETFIELD,
499                    ofproto.OFPTFPT_APPLY_SETFIELD_MISS,
500                    ofproto.OFPTFPT_WRITE_COPYFIELD,
501                    ofproto.OFPTFPT_WRITE_COPYFIELD_MISS,
502                    ofproto.OFPTFPT_APPLY_COPYFIELD,
503                    ofproto.OFPTFPT_APPLY_COPYFIELD_MISS]
504
505     p_type_experimenter = [ofproto.OFPTFPT_EXPERIMENTER,
506                            ofproto.OFPTFPT_EXPERIMENTER_MISS]
507
508     tables = []
509     for msg in msgs:
510         stats = msg.body
511         for stat in stats:
512             s = stat.to_jsondict()[stat.__class__.__name__]
513             properties = []
514             for prop in stat.properties:
515                 p = {}
516                 t = UTIL.ofp_table_feature_prop_type_to_user(prop.type)
517                 p['type'] = t if t != prop.type else 'UNKNOWN'
518                 if prop.type in p_type_instructions:
519                     instruction_ids = []
520                     for i in prop.instruction_ids:
521                         inst = {'len': i.len,
522                                 'type': i.type}
523                         instruction_ids.append(inst)
524                     p['instruction_ids'] = instruction_ids
525                 elif prop.type in p_type_next_tables:
526                     table_ids = []
527                     for i in prop.table_ids:
528                         table_ids.append(i)
529                     p['table_ids'] = table_ids
530                 elif prop.type in p_type_actions:
531                     action_ids = []
532                     for i in prop.action_ids:
533                         act = i.to_jsondict()[i.__class__.__name__]
534                         action_ids.append(act)
535                     p['action_ids'] = action_ids
536                 elif prop.type in p_type_oxms:
537                     oxm_ids = []
538                     for i in prop.oxm_ids:
539                         oxm = i.to_jsondict()[i.__class__.__name__]
540                         oxm_ids.append(oxm)
541                     p['oxm_ids'] = oxm_ids
542                 elif prop.type == p_type_packet:
543                     oxm_values = []
544                     for val in prop.oxm_values:
545                         i = {val[0]: val[1]}
546                         oxm_values.append(i)
547                     p['oxm_values'] = oxm_values
548                 elif prop.type in p_type_experimenter:
549                     pass
550                 properties.append(p)
551             s['name'] = stat.name.decode('utf-8')
552             s['properties'] = properties
553
554             if to_user:
555                 s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
556
557             tables.append(s)
558
559     return wrap_dpid_dict(dp, tables, to_user)
560
561
562 def get_port_stats(dp, waiters, port_no=None, to_user=True):
563     if port_no is None:
564         port_no = dp.ofproto.OFPP_ANY
565     else:
566         port_no = UTIL.ofp_port_from_user(port_no)
567
568     stats = dp.ofproto_parser.OFPPortStatsRequest(dp, 0, port_no)
569     msgs = []
570     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
571
572     ports = []
573     for msg in msgs:
574         for stats in msg.body:
575             s = stats.to_jsondict()[stats.__class__.__name__]
576             properties = []
577             for prop in stats.properties:
578                 p = prop.to_jsondict()[prop.__class__.__name__]
579                 t = UTIL.ofp_port_stats_prop_type_to_user(prop.type)
580                 p['type'] = t if t != prop.type else 'UNKNOWN'
581                 properties.append(p)
582             s['properties'] = properties
583
584             if to_user:
585                 s['port_no'] = UTIL.ofp_port_to_user(stats.port_no)
586
587             ports.append(s)
588
589     return wrap_dpid_dict(dp, ports, to_user)
590
591
592 def get_meter_stats(dp, waiters, meter_id=None, to_user=True):
593     if meter_id is None:
594         meter_id = dp.ofproto.OFPM_ALL
595     else:
596         meter_id = UTIL.ofp_meter_from_user(meter_id)
597
598     stats = dp.ofproto_parser.OFPMeterStatsRequest(
599         dp, 0, meter_id)
600     msgs = []
601     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
602
603     meters = []
604     for msg in msgs:
605         for stats in msg.body:
606             s = stats.to_jsondict()[stats.__class__.__name__]
607             bands = []
608             for band in stats.band_stats:
609                 b = band.to_jsondict()[band.__class__.__name__]
610                 bands.append(b)
611             s['band_stats'] = bands
612
613             if to_user:
614                 s['meter_id'] = UTIL.ofp_meter_to_user(stats.meter_id)
615
616             meters.append(s)
617
618     return wrap_dpid_dict(dp, meters, to_user)
619
620
621 def get_meter_features(dp, waiters, to_user=True):
622     ofp = dp.ofproto
623     type_convert = {ofp.OFPMBT_DROP: 'DROP',
624                     ofp.OFPMBT_DSCP_REMARK: 'DSCP_REMARK'}
625
626     capa_convert = {ofp.OFPMF_KBPS: 'KBPS',
627                     ofp.OFPMF_PKTPS: 'PKTPS',
628                     ofp.OFPMF_BURST: 'BURST',
629                     ofp.OFPMF_STATS: 'STATS'}
630
631     stats = dp.ofproto_parser.OFPMeterFeaturesStatsRequest(dp, 0)
632     msgs = []
633     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
634
635     features = []
636     for msg in msgs:
637         for feature in msg.body:
638             band_types = []
639             for k, v in type_convert.items():
640                 if (1 << k) & feature.band_types:
641
642                     if to_user:
643                         band_types.append(v)
644
645                     else:
646                         band_types.append(k)
647
648             capabilities = []
649             for k, v in sorted(capa_convert.items()):
650                 if k & feature.capabilities:
651
652                     if to_user:
653                         capabilities.append(v)
654
655                     else:
656                         capabilities.append(k)
657
658             f = {'max_meter': feature.max_meter,
659                  'band_types': band_types,
660                  'capabilities': capabilities,
661                  'max_bands': feature.max_bands,
662                  'max_color': feature.max_color}
663             features.append(f)
664
665     return wrap_dpid_dict(dp, features, to_user)
666
667
668 def get_meter_desc(dp, waiters, meter_id=None, to_user=True):
669     flags = {dp.ofproto.OFPMF_KBPS: 'KBPS',
670              dp.ofproto.OFPMF_PKTPS: 'PKTPS',
671              dp.ofproto.OFPMF_BURST: 'BURST',
672              dp.ofproto.OFPMF_STATS: 'STATS'}
673
674     if meter_id is None:
675         meter_id = dp.ofproto.OFPM_ALL
676     else:
677         meter_id = UTIL.ofp_meter_from_user(meter_id)
678
679     stats = dp.ofproto_parser.OFPMeterDescStatsRequest(
680         dp, 0, meter_id)
681     msgs = []
682     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
683
684     configs = []
685     for msg in msgs:
686         for config in msg.body:
687             c = config.to_jsondict()[config.__class__.__name__]
688             bands = []
689             for band in config.bands:
690                 b = band.to_jsondict()[band.__class__.__name__]
691
692                 if to_user:
693                     t = UTIL.ofp_meter_band_type_to_user(band.type)
694                     b['type'] = t if t != band.type else 'UNKNOWN'
695
696                 bands.append(b)
697             c_flags = []
698             for k, v in sorted(flags.items()):
699                 if k & config.flags:
700                     if to_user:
701                         c_flags.append(v)
702
703                     else:
704                         c_flags.append(k)
705
706             c['flags'] = c_flags
707             c['bands'] = bands
708
709             if to_user:
710                 c['meter_id'] = UTIL.ofp_meter_to_user(config.meter_id)
711
712             configs.append(c)
713
714     return wrap_dpid_dict(dp, configs, to_user)
715
716
717 def get_group_stats(dp, waiters, group_id=None, to_user=True):
718     if group_id is None:
719         group_id = dp.ofproto.OFPG_ALL
720     else:
721         group_id = UTIL.ofp_group_from_user(group_id)
722
723     stats = dp.ofproto_parser.OFPGroupStatsRequest(
724         dp, 0, group_id)
725     msgs = []
726     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
727
728     groups = []
729     for msg in msgs:
730         for stats in msg.body:
731             g = stats.to_jsondict()[stats.__class__.__name__]
732             bucket_stats = []
733             for bucket_stat in stats.bucket_stats:
734                 c = bucket_stat.to_jsondict()[bucket_stat.__class__.__name__]
735                 bucket_stats.append(c)
736             g['bucket_stats'] = bucket_stats
737
738             if to_user:
739                 g['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
740
741             groups.append(g)
742
743     return wrap_dpid_dict(dp, groups, to_user)
744
745
746 def get_group_features(dp, waiters, to_user=True):
747
748     ofp = dp.ofproto
749     type_convert = {ofp.OFPGT_ALL: 'ALL',
750                     ofp.OFPGT_SELECT: 'SELECT',
751                     ofp.OFPGT_INDIRECT: 'INDIRECT',
752                     ofp.OFPGT_FF: 'FF'}
753     cap_convert = {ofp.OFPGFC_SELECT_WEIGHT: 'SELECT_WEIGHT',
754                    ofp.OFPGFC_SELECT_LIVENESS: 'SELECT_LIVENESS',
755                    ofp.OFPGFC_CHAINING: 'CHAINING',
756                    ofp.OFPGFC_CHAINING_CHECKS: 'CHAINING_CHECKS'}
757     act_convert = {ofp.OFPAT_OUTPUT: 'OUTPUT',
758                    ofp.OFPAT_COPY_TTL_OUT: 'COPY_TTL_OUT',
759                    ofp.OFPAT_COPY_TTL_IN: 'COPY_TTL_IN',
760                    ofp.OFPAT_SET_MPLS_TTL: 'SET_MPLS_TTL',
761                    ofp.OFPAT_DEC_MPLS_TTL: 'DEC_MPLS_TTL',
762                    ofp.OFPAT_PUSH_VLAN: 'PUSH_VLAN',
763                    ofp.OFPAT_POP_VLAN: 'POP_VLAN',
764                    ofp.OFPAT_PUSH_MPLS: 'PUSH_MPLS',
765                    ofp.OFPAT_POP_MPLS: 'POP_MPLS',
766                    ofp.OFPAT_SET_QUEUE: 'SET_QUEUE',
767                    ofp.OFPAT_GROUP: 'GROUP',
768                    ofp.OFPAT_SET_NW_TTL: 'SET_NW_TTL',
769                    ofp.OFPAT_DEC_NW_TTL: 'DEC_NW_TTL',
770                    ofp.OFPAT_SET_FIELD: 'SET_FIELD',
771                    ofp.OFPAT_PUSH_PBB: 'PUSH_PBB',
772                    ofp.OFPAT_POP_PBB: 'POP_PBB',
773                    ofp.OFPAT_COPY_FIELD: 'COPY_FIELD',
774                    ofp.OFPAT_METER: 'METER',
775                    ofp.OFPAT_EXPERIMENTER: 'EXPERIMENTER'}
776
777     stats = dp.ofproto_parser.OFPGroupFeaturesStatsRequest(dp, 0)
778     msgs = []
779     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
780
781     features = []
782     for msg in msgs:
783         feature = msg.body
784         types = []
785         for k, v in type_convert.items():
786             if (1 << k) & feature.types:
787                 if to_user:
788                     types.append(v)
789
790                 else:
791                     types.append(k)
792
793         capabilities = []
794         for k, v in cap_convert.items():
795             if k & feature.capabilities:
796                 if to_user:
797                     capabilities.append(v)
798
799                 else:
800                     capabilities.append(k)
801
802         if to_user:
803             max_groups = []
804             for k, v in type_convert.items():
805                 max_groups.append({v: feature.max_groups[k]})
806
807         else:
808             max_groups = feature.max_groups
809
810         actions = []
811         for k1, v1 in type_convert.items():
812             acts = []
813             for k2, v2 in act_convert.items():
814                 if (1 << k2) & feature.actions[k1]:
815                     if to_user:
816                         acts.append(v2)
817
818                     else:
819                         acts.append(k2)
820
821             if to_user:
822                 actions.append({v1: acts})
823
824             else:
825                 actions.append({k1: acts})
826
827         f = {'types': types,
828              'capabilities': capabilities,
829              'max_groups': max_groups,
830              'actions': actions}
831         features.append(f)
832
833     return wrap_dpid_dict(dp, features, to_user)
834
835
836 def get_group_desc(dp, waiters, group_id=None, to_user=True):
837     if group_id is None:
838         group_id = dp.ofproto.OFPG_ALL
839     else:
840         group_id = UTIL.ofp_group_from_user(group_id)
841
842     stats = dp.ofproto_parser.OFPGroupDescStatsRequest(dp, 0, group_id)
843     msgs = []
844     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
845
846     descs = []
847     for msg in msgs:
848         for stats in msg.body:
849             d = stats.to_jsondict()[stats.__class__.__name__]
850             buckets = []
851             for bucket in stats.buckets:
852                 b = bucket.to_jsondict()[bucket.__class__.__name__]
853                 actions = []
854                 for action in bucket.actions:
855                     if to_user:
856                         actions.append(action_to_str(action))
857
858                     else:
859                         actions.append(action)
860                 properties = []
861                 for prop in bucket.properties:
862                     p = prop.to_jsondict()[prop.__class__.__name__]
863                     t = UTIL.ofp_group_bucket_prop_type_to_user(prop.type)
864                     p['type'] = t if t != prop.type else 'UNKNOWN'
865                     properties.append(p)
866                 b['actions'] = actions
867                 b['properties'] = properties
868                 buckets.append(b)
869
870             d['buckets'] = buckets
871             if to_user:
872                 d['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
873                 t = UTIL.ofp_group_type_to_user(stats.type)
874                 d['type'] = t if t != stats.type else 'UNKNOWN'
875
876             descs.append(d)
877
878     return wrap_dpid_dict(dp, descs, to_user)
879
880
881 def get_port_desc(dp, waiters, port_no=None, to_user=True):
882     if port_no is None:
883         port_no = dp.ofproto.OFPP_ANY
884     else:
885         port_no = UTIL.ofp_port_from_user(port_no)
886
887     stats = dp.ofproto_parser.OFPPortDescStatsRequest(dp, 0, port_no)
888     msgs = []
889     ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
890
891     descs = []
892
893     for msg in msgs:
894         stats = msg.body
895         for stat in stats:
896             d = stat.to_jsondict()[stat.__class__.__name__]
897             properties = []
898             for prop in stat.properties:
899                 p = prop.to_jsondict()[prop.__class__.__name__]
900
901                 if to_user:
902                     t = UTIL.ofp_port_desc_prop_type_to_user(prop.type)
903                     p['type'] = t if t != prop.type else 'UNKNOWN'
904
905                 properties.append(p)
906             d['name'] = stat.name.decode('utf-8')
907             d['properties'] = properties
908
909             if to_user:
910                 d['port_no'] = UTIL.ofp_port_to_user(stat.port_no)
911
912             descs.append(d)
913
914     return wrap_dpid_dict(dp, descs, to_user)
915
916
917 def get_role(dp, waiters, to_user=True):
918     return ofctl_utils.get_role(dp, waiters, to_user)
919
920
921 def mod_flow_entry(dp, flow, cmd):
922     cookie = str_to_int(flow.get('cookie', 0))
923     cookie_mask = str_to_int(flow.get('cookie_mask', 0))
924     table_id = UTIL.ofp_table_from_user(flow.get('table_id', 0))
925     idle_timeout = str_to_int(flow.get('idle_timeout', 0))
926     hard_timeout = str_to_int(flow.get('hard_timeout', 0))
927     priority = str_to_int(flow.get('priority', 0))
928     buffer_id = UTIL.ofp_buffer_from_user(
929         flow.get('buffer_id', dp.ofproto.OFP_NO_BUFFER))
930     out_port = UTIL.ofp_port_from_user(
931         flow.get('out_port', dp.ofproto.OFPP_ANY))
932     out_group = UTIL.ofp_group_from_user(
933         flow.get('out_group', dp.ofproto.OFPG_ANY))
934     importance = str_to_int(flow.get('importance', 0))
935     flags = str_to_int(flow.get('flags', 0))
936     match = to_match(dp, flow.get('match', {}))
937     inst = to_instructions(dp, flow.get('instructions', []))
938
939     flow_mod = dp.ofproto_parser.OFPFlowMod(
940         dp, cookie, cookie_mask, table_id, cmd, idle_timeout,
941         hard_timeout, priority, buffer_id, out_port, out_group,
942         importance, flags, match, inst)
943
944     ofctl_utils.send_msg(dp, flow_mod, LOG)
945
946
947 def mod_meter_entry(dp, meter, cmd):
948     flags = 0
949     if 'flags' in meter:
950         meter_flags = meter['flags']
951         if not isinstance(meter_flags, list):
952             meter_flags = [meter_flags]
953         for flag in meter_flags:
954             t = UTIL.ofp_meter_flags_from_user(flag)
955             f = t if t != flag else None
956             if f is None:
957                 LOG.error('Unknown meter flag: %s', flag)
958                 continue
959             flags |= f
960
961     meter_id = UTIL.ofp_meter_from_user(meter.get('meter_id', 0))
962
963     bands = []
964     for band in meter.get('bands', []):
965         band_type = band.get('type')
966         rate = str_to_int(band.get('rate', 0))
967         burst_size = str_to_int(band.get('burst_size', 0))
968         if band_type == 'DROP':
969             bands.append(
970                 dp.ofproto_parser.OFPMeterBandDrop(rate, burst_size))
971         elif band_type == 'DSCP_REMARK':
972             prec_level = str_to_int(band.get('prec_level', 0))
973             bands.append(
974                 dp.ofproto_parser.OFPMeterBandDscpRemark(
975                     rate, burst_size, prec_level))
976         elif band_type == 'EXPERIMENTER':
977             experimenter = str_to_int(band.get('experimenter', 0))
978             bands.append(
979                 dp.ofproto_parser.OFPMeterBandExperimenter(
980                     rate, burst_size, experimenter))
981         else:
982             LOG.error('Unknown band type: %s', band_type)
983
984     meter_mod = dp.ofproto_parser.OFPMeterMod(
985         dp, cmd, flags, meter_id, bands)
986
987     ofctl_utils.send_msg(dp, meter_mod, LOG)
988
989
990 def mod_group_entry(dp, group, cmd):
991     ofp = dp.ofproto
992     parser = dp.ofproto_parser
993
994     group_type = str(group.get('type', 'ALL'))
995     t = UTIL.ofp_group_type_from_user(group_type)
996     group_type = t if t != group_type else None
997     if group_type is None:
998         LOG.error('Unknown group type: %s', group.get('type'))
999
1000     group_id = UTIL.ofp_group_from_user(group.get('group_id', 0))
1001     command_bucket_id = str_to_int(group.get('command_bucket_id', 0))
1002
1003     # Note:
1004     # The list of group property types that are currently defined
1005     # are only OFPGPT_EXPERIMENTER(Experimenter defined).
1006     properties = []
1007
1008     buckets = []
1009     for bucket in group.get('buckets', []):
1010
1011         # get bucket_id in buckets
1012         bucket_id = str_to_int(bucket.get('bucket_id', 0))
1013
1014         # get actions in buckets
1015         bucket_actions = []
1016         for dic in bucket.get('actions', []):
1017             action = to_action(dp, dic)
1018             if action is not None:
1019                 bucket_actions.append(action)
1020
1021         # get properties in buckets
1022         bucket_properties = []
1023         for p in bucket.get('properties', []):
1024             group_bp_type = str(p.get('type', 'WEIGHT'))
1025             t = UTIL.ofp_group_bucket_prop_type_from_user(group_bp_type)
1026             group_bp_type = t if t != group_bp_type else ofp.OFPGBPT_WEIGHT
1027
1028             if group_bp_type == ofp.OFPGBPT_WEIGHT:
1029                 weight = str_to_int(p.get('weight', 0))
1030                 bucket_properties.append(
1031                     parser.OFPGroupBucketPropWeight(
1032                         type_=group_bp_type, weight=weight))
1033             elif group_bp_type == ofp.OFPGBPT_WATCH_PORT:
1034                 watch_port = str_to_int(p.get('watch', dp.ofproto.OFPP_ANY))
1035                 bucket_properties.append(
1036                     parser.OFPGroupBucketPropWatch(
1037                         type_=group_bp_type, watch=watch_port))
1038             elif group_bp_type == ofp.OFPGBPT_WATCH_GROUP:
1039                 watch_group = str_to_int(p.get('watch', dp.ofproto.OFPG_ANY))
1040                 bucket_properties.append(
1041                     parser.OFPGroupBucketPropWatch(
1042                         type_=group_bp_type, watch=watch_group))
1043             elif group_bp_type == ofp.OFPGBPT_EXPERIMENTER:
1044                 experimenter = p.get('experimenter', 0)
1045                 exp_type = p.get('exp_type', 0)
1046                 data_type = p.get('data_type', 'ascii')
1047                 if data_type not in ['ascii', 'base64']:
1048                     LOG.error('Unknown data type: %s', data_type)
1049                 data = p.get('data', '')
1050                 if data_type == 'base64':
1051                     data = base64.b64decode(data)
1052                 bucket_properties.append(
1053                     parser.OFPGroupBucketPropExperimenter(
1054                         type_=group_bp_type, experimenter=experimenter,
1055                         exp_type=exp_type, data=data))
1056             else:
1057                 LOG.error('Unknown group bucket prop type: %s', p['type'])
1058
1059         # create bucket
1060         bucket = parser.OFPBucket(bucket_id=bucket_id,
1061                                   actions=bucket_actions,
1062                                   properties=bucket_properties)
1063         buckets.append(bucket)
1064
1065     group_mod = parser.OFPGroupMod(dp, cmd, group_type, group_id,
1066                                    command_bucket_id, buckets,
1067                                    properties)
1068
1069     ofctl_utils.send_msg(dp, group_mod, LOG)
1070
1071
1072 def mod_port_behavior(dp, port_config):
1073     ofp = dp.ofproto
1074     parser = dp.ofproto_parser
1075     port_no = UTIL.ofp_port_from_user(port_config.get('port_no', 0))
1076     hw_addr = str(port_config.get('hw_addr'))
1077     config = str_to_int(port_config.get('config', 0))
1078     mask = str_to_int(port_config.get('mask', 0))
1079     properties = port_config.get('properties')
1080
1081     prop = []
1082     for p in properties:
1083         type_ = UTIL.ofp_port_mod_prop_type_from_user(p['type'])
1084         length = None
1085         if type_ == ofp.OFPPDPT_ETHERNET:
1086             advertise = UTIL.ofp_port_features_from_user(p['advertise'])
1087             prop.append(
1088                 parser.OFPPortModPropEthernet(type_, length, advertise))
1089         elif type_ == ofp.OFPPDPT_OPTICAL:
1090             prop.append(
1091                 parser.OFPPortModPropOptical(
1092                     type_, length, p['configure'], p['freq_lmda'],
1093                     p['fl_offset'], p['grid_span'], p['tx_pwr']))
1094         elif type_ == ofp.OFPPDPT_EXPERIMENTER:
1095             prop.append(
1096                 parser.OFPPortModPropExperimenter(
1097                     type_, length, p['experimenter'], p['exp_type'],
1098                     p['data']))
1099         else:
1100             LOG.error('Unknown port desc prop type: %s', type_)
1101
1102     port_mod = dp.ofproto_parser.OFPPortMod(
1103         dp, port_no, hw_addr, config, mask, prop)
1104
1105     ofctl_utils.send_msg(dp, port_mod, LOG)
1106
1107
1108 def set_role(dp, role):
1109     r = UTIL.ofp_role_from_user(role.get('role', dp.ofproto.OFPCR_ROLE_EQUAL))
1110     role_request = dp.ofproto_parser.OFPRoleRequest(dp, r, None, 0)
1111     ofctl_utils.send_msg(dp, role_request, LOG)
1112
1113
1114 # NOTE(jkoelker) Alias common funcitons
1115 send_experimenter = ofctl_utils.send_experimenter