1 # Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
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
7 # http://www.apache.org/licenses/LICENSE-2.0
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
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
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
24 LOG = logging.getLogger(__name__)
28 UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_5)
29 str_to_int = ofctl_utils.str_to_int
32 def to_action(dp, dic):
34 parser = dp.ofproto_parser
35 action_type = dic.get('type')
36 return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL)
39 def _get_actions(dp, dics):
42 action = to_action(dp, d)
43 if action is not None:
44 actions.append(action)
46 LOG.error('Unknown action type: %s', d)
50 def to_instructions(dp, insts):
53 parser = dp.ofproto_parser
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)
61 if inst_type == 'APPLY_ACTIONS':
63 parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
67 parser.OFPInstructionActions(ofp.OFPIT_WRITE_ACTIONS,
69 elif inst_type == 'CLEAR_ACTIONS':
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)
81 parser.OFPInstructionWriteMetadata(
82 metadata, metadata_mask))
84 LOG.error('Unknown instruction type: %s', inst_type)
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'
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']
107 def instructions_to_str(instructions):
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):
119 acts.append(action_to_str(a))
120 v['type'] = inst_type
125 v['type'] = inst_type
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}
177 keys = {'dl_dst': 'eth_dst',
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'}
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']
194 for key, value in attrs.items():
199 value = convert[key](value)
202 LOG.error('Unknown match field: %s', key)
204 return dp.ofproto_parser.OFPMatch(**kwargs)
207 def to_match_vid(value):
208 return ofctl_utils.to_match_vid(value, ofproto_v1_5.OFPVID_PRESENT)
211 def match_to_str(ofmatch):
214 ofmatch = ofmatch.to_jsondict()['OFPMatch']
215 ofmatch = ofmatch['oxm_fields']
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]
229 value = str(value) + '/' + str(mask)
230 match.setdefault(key, value)
235 def match_vid_to_str(value, mask):
236 return ofctl_utils.match_vid_to_str(
237 value, mask, ofproto_v1_5.OFPVID_PRESENT)
240 def wrap_dpid_dict(dp, value, to_user=True):
242 return {str(dp.id): value}
244 return {dp.id: value}
247 def stats_to_str(ofstats):
250 ofstats = ofstats.to_jsondict()['OFPStats']
251 ofstats = ofstats['oxs_fields']
254 key = s['OXSTlv']['field']
255 if key == 'duration':
257 'duration_sec': s['OXSTlv']['value'][0],
258 'duration_nsec': s['OXSTlv']['value'][1],
260 elif key == 'idle_time':
262 'idle_time_sec': s['OXSTlv']['value'][0],
263 'idle_time_nsec': s['OXSTlv']['value'][1],
266 value = s['OXSTlv']['value']
267 stats.setdefault(key, value)
272 def get_desc_stats(dp, waiters, to_user=True):
273 stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0)
275 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
280 s = stats.to_jsondict()[stats.__class__.__name__]
282 return wrap_dpid_dict(dp, s, to_user)
285 def get_queue_stats(dp, waiters, port_no=None, queue_id=None, to_user=True):
287 port_no = dp.ofproto.OFPP_ANY
289 port_no = UTIL.ofp_port_from_user(port_no)
291 queue_id = dp.ofproto.OFPQ_ALL
293 queue_id = UTIL.ofp_queue_from_user(queue_id)
295 stats = dp.ofproto_parser.OFPQueueStatsRequest(
296 dp, 0, port_no, queue_id)
298 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
304 s = stat.to_jsondict()[stat.__class__.__name__]
306 for prop in stat.properties:
307 p = prop.to_jsondict()[prop.__class__.__name__]
309 t = UTIL.ofp_queue_stats_prop_type_to_user(prop.type)
310 p['type'] = t if t != p['type'] else 'UNKNOWN'
312 s['properties'] = properties
315 return wrap_dpid_dict(dp, desc, to_user)
318 def get_queue_desc(dp, waiters, port_no=None, queue_id=None, to_user=True):
320 port_no = dp.ofproto.OFPP_ANY
322 port_no = UTIL.ofp_port_from_user(port_no)
324 queue_id = dp.ofproto.OFPQ_ALL
326 queue_id = UTIL.ofp_queue_from_user(queue_id)
328 stats = dp.ofproto_parser.OFPQueueDescStatsRequest(
329 dp, 0, port_no, queue_id)
331 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
335 for queue in msg.body:
336 q = queue.to_jsondict()[queue.__class__.__name__]
338 for prop in queue.properties:
339 p = prop.to_jsondict()[prop.__class__.__name__]
341 t = UTIL.ofp_queue_desc_prop_type_to_user(prop.type)
342 p['type'] = t if t != prop.type else 'UNKNOWN'
344 q['properties'] = prop_list
347 return wrap_dpid_dict(dp, configs, to_user)
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))
366 stats = dp.ofproto_parser.OFPFlowDescStatsRequest(
367 dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
371 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
375 for stats in msg.body:
376 if 0 <= priority != stats.priority:
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)
385 return wrap_dpid_dict(dp, flows, to_user)
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))
404 stats = dp.ofproto_parser.OFPFlowStatsRequest(
405 dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
409 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
413 for stats in msg.body:
414 if 0 <= priority != stats.priority:
417 s = stats.to_jsondict()[stats.__class__.__name__]
418 s['stats'] = stats_to_str(stats.stats)
419 s['match'] = match_to_str(stats.match)
422 return wrap_dpid_dict(dp, flows, to_user)
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', {}))
438 stats = dp.ofproto_parser.OFPAggregateStatsRequest(
439 dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
443 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
448 s = stats.to_jsondict()[stats.__class__.__name__]
449 s['stats'] = stats_to_str(stats.stats)
452 return wrap_dpid_dict(dp, flows, to_user)
455 def get_table_stats(dp, waiters, to_user=True):
456 stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0)
458 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
464 s = stat.to_jsondict()[stat.__class__.__name__]
467 s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
471 return wrap_dpid_dict(dp, tables, to_user)
474 def get_table_features(dp, waiters, to_user=True):
475 stats = dp.ofproto_parser.OFPTableFeaturesStatsRequest(dp, 0, [])
478 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
480 p_type_instructions = [ofproto.OFPTFPT_INSTRUCTIONS,
481 ofproto.OFPTFPT_INSTRUCTIONS_MISS]
483 p_type_next_tables = [ofproto.OFPTFPT_NEXT_TABLES,
484 ofproto.OFPTFPT_NEXT_TABLES_MISS,
485 ofproto.OFPTFPT_TABLE_SYNC_FROM]
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]
492 p_type_packet = ofproto.OFPTFPT_PACKET_TYPES
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]
505 p_type_experimenter = [ofproto.OFPTFPT_EXPERIMENTER,
506 ofproto.OFPTFPT_EXPERIMENTER_MISS]
512 s = stat.to_jsondict()[stat.__class__.__name__]
514 for prop in stat.properties:
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:
520 for i in prop.instruction_ids:
521 inst = {'len': i.len,
523 instruction_ids.append(inst)
524 p['instruction_ids'] = instruction_ids
525 elif prop.type in p_type_next_tables:
527 for i in prop.table_ids:
529 p['table_ids'] = table_ids
530 elif prop.type in p_type_actions:
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:
538 for i in prop.oxm_ids:
539 oxm = i.to_jsondict()[i.__class__.__name__]
541 p['oxm_ids'] = oxm_ids
542 elif prop.type == p_type_packet:
544 for val in prop.oxm_values:
547 p['oxm_values'] = oxm_values
548 elif prop.type in p_type_experimenter:
551 s['name'] = stat.name.decode('utf-8')
552 s['properties'] = properties
555 s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
559 return wrap_dpid_dict(dp, tables, to_user)
562 def get_port_stats(dp, waiters, port_no=None, to_user=True):
564 port_no = dp.ofproto.OFPP_ANY
566 port_no = UTIL.ofp_port_from_user(port_no)
568 stats = dp.ofproto_parser.OFPPortStatsRequest(dp, 0, port_no)
570 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
574 for stats in msg.body:
575 s = stats.to_jsondict()[stats.__class__.__name__]
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'
582 s['properties'] = properties
585 s['port_no'] = UTIL.ofp_port_to_user(stats.port_no)
589 return wrap_dpid_dict(dp, ports, to_user)
592 def get_meter_stats(dp, waiters, meter_id=None, to_user=True):
594 meter_id = dp.ofproto.OFPM_ALL
596 meter_id = UTIL.ofp_meter_from_user(meter_id)
598 stats = dp.ofproto_parser.OFPMeterStatsRequest(
601 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
605 for stats in msg.body:
606 s = stats.to_jsondict()[stats.__class__.__name__]
608 for band in stats.band_stats:
609 b = band.to_jsondict()[band.__class__.__name__]
611 s['band_stats'] = bands
614 s['meter_id'] = UTIL.ofp_meter_to_user(stats.meter_id)
618 return wrap_dpid_dict(dp, meters, to_user)
621 def get_meter_features(dp, waiters, to_user=True):
623 type_convert = {ofp.OFPMBT_DROP: 'DROP',
624 ofp.OFPMBT_DSCP_REMARK: 'DSCP_REMARK'}
626 capa_convert = {ofp.OFPMF_KBPS: 'KBPS',
627 ofp.OFPMF_PKTPS: 'PKTPS',
628 ofp.OFPMF_BURST: 'BURST',
629 ofp.OFPMF_STATS: 'STATS'}
631 stats = dp.ofproto_parser.OFPMeterFeaturesStatsRequest(dp, 0)
633 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
637 for feature in msg.body:
639 for k, v in type_convert.items():
640 if (1 << k) & feature.band_types:
649 for k, v in sorted(capa_convert.items()):
650 if k & feature.capabilities:
653 capabilities.append(v)
656 capabilities.append(k)
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}
665 return wrap_dpid_dict(dp, features, to_user)
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'}
675 meter_id = dp.ofproto.OFPM_ALL
677 meter_id = UTIL.ofp_meter_from_user(meter_id)
679 stats = dp.ofproto_parser.OFPMeterDescStatsRequest(
682 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
686 for config in msg.body:
687 c = config.to_jsondict()[config.__class__.__name__]
689 for band in config.bands:
690 b = band.to_jsondict()[band.__class__.__name__]
693 t = UTIL.ofp_meter_band_type_to_user(band.type)
694 b['type'] = t if t != band.type else 'UNKNOWN'
698 for k, v in sorted(flags.items()):
710 c['meter_id'] = UTIL.ofp_meter_to_user(config.meter_id)
714 return wrap_dpid_dict(dp, configs, to_user)
717 def get_group_stats(dp, waiters, group_id=None, to_user=True):
719 group_id = dp.ofproto.OFPG_ALL
721 group_id = UTIL.ofp_group_from_user(group_id)
723 stats = dp.ofproto_parser.OFPGroupStatsRequest(
726 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
730 for stats in msg.body:
731 g = stats.to_jsondict()[stats.__class__.__name__]
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
739 g['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
743 return wrap_dpid_dict(dp, groups, to_user)
746 def get_group_features(dp, waiters, to_user=True):
749 type_convert = {ofp.OFPGT_ALL: 'ALL',
750 ofp.OFPGT_SELECT: 'SELECT',
751 ofp.OFPGT_INDIRECT: 'INDIRECT',
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'}
777 stats = dp.ofproto_parser.OFPGroupFeaturesStatsRequest(dp, 0)
779 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
785 for k, v in type_convert.items():
786 if (1 << k) & feature.types:
794 for k, v in cap_convert.items():
795 if k & feature.capabilities:
797 capabilities.append(v)
800 capabilities.append(k)
804 for k, v in type_convert.items():
805 max_groups.append({v: feature.max_groups[k]})
808 max_groups = feature.max_groups
811 for k1, v1 in type_convert.items():
813 for k2, v2 in act_convert.items():
814 if (1 << k2) & feature.actions[k1]:
822 actions.append({v1: acts})
825 actions.append({k1: acts})
828 'capabilities': capabilities,
829 'max_groups': max_groups,
833 return wrap_dpid_dict(dp, features, to_user)
836 def get_group_desc(dp, waiters, group_id=None, to_user=True):
838 group_id = dp.ofproto.OFPG_ALL
840 group_id = UTIL.ofp_group_from_user(group_id)
842 stats = dp.ofproto_parser.OFPGroupDescStatsRequest(dp, 0, group_id)
844 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
848 for stats in msg.body:
849 d = stats.to_jsondict()[stats.__class__.__name__]
851 for bucket in stats.buckets:
852 b = bucket.to_jsondict()[bucket.__class__.__name__]
854 for action in bucket.actions:
856 actions.append(action_to_str(action))
859 actions.append(action)
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'
866 b['actions'] = actions
867 b['properties'] = properties
870 d['buckets'] = buckets
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'
878 return wrap_dpid_dict(dp, descs, to_user)
881 def get_port_desc(dp, waiters, port_no=None, to_user=True):
883 port_no = dp.ofproto.OFPP_ANY
885 port_no = UTIL.ofp_port_from_user(port_no)
887 stats = dp.ofproto_parser.OFPPortDescStatsRequest(dp, 0, port_no)
889 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
896 d = stat.to_jsondict()[stat.__class__.__name__]
898 for prop in stat.properties:
899 p = prop.to_jsondict()[prop.__class__.__name__]
902 t = UTIL.ofp_port_desc_prop_type_to_user(prop.type)
903 p['type'] = t if t != prop.type else 'UNKNOWN'
906 d['name'] = stat.name.decode('utf-8')
907 d['properties'] = properties
910 d['port_no'] = UTIL.ofp_port_to_user(stat.port_no)
914 return wrap_dpid_dict(dp, descs, to_user)
917 def get_role(dp, waiters, to_user=True):
918 return ofctl_utils.get_role(dp, waiters, to_user)
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', []))
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)
944 ofctl_utils.send_msg(dp, flow_mod, LOG)
947 def mod_meter_entry(dp, meter, cmd):
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
957 LOG.error('Unknown meter flag: %s', flag)
961 meter_id = UTIL.ofp_meter_from_user(meter.get('meter_id', 0))
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':
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))
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))
979 dp.ofproto_parser.OFPMeterBandExperimenter(
980 rate, burst_size, experimenter))
982 LOG.error('Unknown band type: %s', band_type)
984 meter_mod = dp.ofproto_parser.OFPMeterMod(
985 dp, cmd, flags, meter_id, bands)
987 ofctl_utils.send_msg(dp, meter_mod, LOG)
990 def mod_group_entry(dp, group, cmd):
992 parser = dp.ofproto_parser
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'))
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))
1004 # The list of group property types that are currently defined
1005 # are only OFPGPT_EXPERIMENTER(Experimenter defined).
1009 for bucket in group.get('buckets', []):
1011 # get bucket_id in buckets
1012 bucket_id = str_to_int(bucket.get('bucket_id', 0))
1014 # get actions in buckets
1016 for dic in bucket.get('actions', []):
1017 action = to_action(dp, dic)
1018 if action is not None:
1019 bucket_actions.append(action)
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
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))
1057 LOG.error('Unknown group bucket prop type: %s', p['type'])
1060 bucket = parser.OFPBucket(bucket_id=bucket_id,
1061 actions=bucket_actions,
1062 properties=bucket_properties)
1063 buckets.append(bucket)
1065 group_mod = parser.OFPGroupMod(dp, cmd, group_type, group_id,
1066 command_bucket_id, buckets,
1069 ofctl_utils.send_msg(dp, group_mod, LOG)
1072 def mod_port_behavior(dp, port_config):
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')
1082 for p in properties:
1083 type_ = UTIL.ofp_port_mod_prop_type_from_user(p['type'])
1085 if type_ == ofp.OFPPDPT_ETHERNET:
1086 advertise = UTIL.ofp_port_features_from_user(p['advertise'])
1088 parser.OFPPortModPropEthernet(type_, length, advertise))
1089 elif type_ == ofp.OFPPDPT_OPTICAL:
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:
1096 parser.OFPPortModPropExperimenter(
1097 type_, length, p['experimenter'], p['exp_type'],
1100 LOG.error('Unknown port desc prop type: %s', type_)
1102 port_mod = dp.ofproto_parser.OFPPortMod(
1103 dp, port_no, hw_addr, config, mask, prop)
1105 ofctl_utils.send_msg(dp, port_mod, LOG)
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)
1114 # NOTE(jkoelker) Alias common funcitons
1115 send_experimenter = ofctl_utils.send_experimenter