summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ryu/lib/ofctl_utils.py37
-rw-r--r--ryu/lib/ofctl_v1_5.py1090
2 files changed, 1125 insertions, 2 deletions
diff --git a/ryu/lib/ofctl_utils.py b/ryu/lib/ofctl_utils.py
index 832baf0b..a4097f87 100644
--- a/ryu/lib/ofctl_utils.py
+++ b/ryu/lib/ofctl_utils.py
@@ -40,8 +40,10 @@ GROUP = 'GROUP'
SET_NW_TTL = 'SET_NW_TTL'
DEC_NW_TTL = 'DEC_NW_TTL'
SET_FIELD = 'SET_FIELD'
-PUSH_PBB = 'PUSH_PBB'
-POP_PBB = 'POP_PBB'
+PUSH_PBB = 'PUSH_PBB' # OpenFlow 1.3 or later
+POP_PBB = 'POP_PBB' # OpenFlow 1.3 or later
+COPY_FIELD = 'COPY_FIELD' # OpenFlow 1.5 or later
+METER = 'METER' # OpenFlow 1.5 or later
EXPERIMENTER = 'EXPERIMENTER'
@@ -109,6 +111,24 @@ def to_action(dic, ofp, parser, action_type, util):
value = dic.get('value')
return parser.OFPActionSetField(**{field: value})
+ elif action_type == 'COPY_FIELD':
+ n_bits = int(dic.get('n_bits'))
+ src_offset = int(dic.get('src_offset'))
+ dst_offset = int(dic.get('dst_offset'))
+ oxm_ids = [parser.OFPOxmId(str(dic.get('src_oxm_id'))),
+ parser.OFPOxmId(str(dic.get('dst_oxm_id')))]
+ return parser.OFPActionCopyField(
+ n_bits, src_offset, dst_offset, oxm_ids)
+
+ elif action_type == 'METER':
+ if hasattr(parser, 'OFPActionMeter'):
+ # OpenFlow 1.5 or later
+ meter_id = int(dic.get('meter_id'))
+ return parser.OFPActionMeter(meter_id)
+ else:
+ # OpenFlow 1.4 or earlier
+ return None
+
elif action_type == EXPERIMENTER:
experimenter = int(dic.get('experimenter'))
data_type = dic.get('data_type', 'ascii')
@@ -179,6 +199,13 @@ def to_match_masked_int(value):
return str_to_int(value)
+def to_match_packet_type(value):
+ if isinstance(value, (list, tuple)):
+ return str_to_int(value[0]) << 16 | str_to_int(value[1])
+ else:
+ return str_to_int(value)
+
+
def send_experimenter(dp, exp, logger=None):
experimenter = exp.get('experimenter', 0)
exp_type = exp.get('exp_type', 0)
@@ -362,6 +389,12 @@ class OFCtlUtil(object):
def ofp_group_capabilities_to_user(self, group):
return self._reserved_num_to_user(group, 'OFPGFC_')
+ def ofp_group_bucket_prop_type_from_user(self, group):
+ return self._reserved_num_from_user(group, 'OFPGBPT_')
+
+ def ofp_group_bucket_prop_type_to_user(self, group):
+ return self._reserved_num_to_user(group, 'OFPGBPT_')
+
def ofp_buffer_from_user(self, buffer):
if buffer in ['OFP_NO_BUFFER', 'NO_BUFFER']:
return self.ofproto.OFP_NO_BUFFER
diff --git a/ryu/lib/ofctl_v1_5.py b/ryu/lib/ofctl_v1_5.py
new file mode 100644
index 00000000..52c2de88
--- /dev/null
+++ b/ryu/lib/ofctl_v1_5.py
@@ -0,0 +1,1090 @@
+# Copyright (C) 2016 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import base64
+import logging
+
+from ryu.ofproto import ether
+from ryu.ofproto import ofproto_v1_5
+from ryu.ofproto import ofproto_v1_5_parser
+from ryu.lib import ofctl_utils
+
+LOG = logging.getLogger(__name__)
+
+DEFAULT_TIMEOUT = 1.0
+
+UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_5)
+
+
+def to_action(dp, dic):
+ ofp = dp.ofproto
+ parser = dp.ofproto_parser
+ action_type = dic.get('type')
+ return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL)
+
+
+def _get_actions(dp, dics):
+ actions = []
+ for d in dics:
+ action = to_action(dp, d)
+ if action is not None:
+ actions.append(action)
+ else:
+ LOG.error('Unknown action type: %s', d)
+ return actions
+
+
+def to_instructions(dp, insts):
+ instructions = []
+ ofp = dp.ofproto
+ parser = dp.ofproto_parser
+
+ for i in insts:
+ inst_type = i.get('type')
+ if inst_type in ['APPLY_ACTIONS', 'WRITE_ACTIONS']:
+ dics = i.get('actions', [])
+ actions = _get_actions(dp, dics)
+ if actions:
+ if inst_type == 'APPLY_ACTIONS':
+ instructions.append(
+ parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
+ actions))
+ else:
+ instructions.append(
+ parser.OFPInstructionActions(ofp.OFPIT_WRITE_ACTIONS,
+ actions))
+ elif inst_type == 'CLEAR_ACTIONS':
+ instructions.append(
+ parser.OFPInstructionActions(ofp.OFPIT_CLEAR_ACTIONS, []))
+ elif inst_type == 'GOTO_TABLE':
+ table_id = int(i.get('table_id'))
+ instructions.append(parser.OFPInstructionGotoTable(table_id))
+ elif inst_type == 'WRITE_METADATA':
+ metadata = ofctl_utils.str_to_int(i.get('metadata'))
+ metadata_mask = (ofctl_utils.str_to_int(i['metadata_mask'])
+ if 'metadata_mask' in i
+ else parser.UINT64_MAX)
+ instructions.append(
+ parser.OFPInstructionWriteMetadata(
+ metadata, metadata_mask))
+ else:
+ LOG.error('Unknown instruction type: %s', inst_type)
+
+ return instructions
+
+
+def action_to_str(act):
+ s = act.to_jsondict()[act.__class__.__name__]
+ t = UTIL.ofp_action_type_to_user(s['type'])
+ s['type'] = t if t != s['type'] else 'UNKNOWN'
+
+ if t == 'SET_FIELD':
+ field = s.pop('field')
+ s['field'] = field['OXMTlv']['field']
+ s['mask'] = field['OXMTlv']['mask']
+ s['value'] = field['OXMTlv']['value']
+ elif t == 'COPY_FIELD':
+ oxm_ids = s.pop('oxm_ids')
+ s['src_oxm_id'] = oxm_ids[0]['OFPOxmId']['type']
+ s['dst_oxm_id'] = oxm_ids[1]['OFPOxmId']['type']
+
+ return s
+
+
+def instructions_to_str(instructions):
+
+ s = []
+
+ for i in instructions:
+ v = i.to_jsondict()[i.__class__.__name__]
+ t = UTIL.ofp_instruction_type_to_user(v['type'])
+ inst_type = t if t != v['type'] else 'UNKNOWN'
+ # apply/write/clear-action instruction
+ if isinstance(i, ofproto_v1_5_parser.OFPInstructionActions):
+ acts = []
+ for a in i.actions:
+ acts.append(action_to_str(a))
+ v['type'] = inst_type
+ v['actions'] = acts
+ s.append(v)
+ # others
+ else:
+ v['type'] = inst_type
+ s.append(v)
+
+ return s
+
+
+def to_match(dp, attrs):
+ convert = {'in_port': UTIL.ofp_port_from_user,
+ 'in_phy_port': int,
+ 'metadata': ofctl_utils.to_match_masked_int,
+ 'eth_dst': ofctl_utils.to_match_eth,
+ 'eth_src': ofctl_utils.to_match_eth,
+ 'eth_type': int,
+ 'vlan_vid': to_match_vid,
+ 'vlan_pcp': int,
+ 'ip_dscp': int,
+ 'ip_ecn': int,
+ 'ip_proto': int,
+ 'ipv4_src': ofctl_utils.to_match_ip,
+ 'ipv4_dst': ofctl_utils.to_match_ip,
+ 'tcp_src': int,
+ 'tcp_dst': int,
+ 'udp_src': int,
+ 'udp_dst': int,
+ 'sctp_src': int,
+ 'sctp_dst': int,
+ 'icmpv4_type': int,
+ 'icmpv4_code': int,
+ 'arp_op': int,
+ 'arp_spa': ofctl_utils.to_match_ip,
+ 'arp_tpa': ofctl_utils.to_match_ip,
+ 'arp_sha': ofctl_utils.to_match_eth,
+ 'arp_tha': ofctl_utils.to_match_eth,
+ 'ipv6_src': ofctl_utils.to_match_ip,
+ 'ipv6_dst': ofctl_utils.to_match_ip,
+ 'ipv6_flabel': int,
+ 'icmpv6_type': int,
+ 'icmpv6_code': int,
+ 'ipv6_nd_target': ofctl_utils.to_match_ip,
+ 'ipv6_nd_sll': ofctl_utils.to_match_eth,
+ 'ipv6_nd_tll': ofctl_utils.to_match_eth,
+ 'mpls_label': int,
+ 'mpls_tc': int,
+ 'mpls_bos': int,
+ 'pbb_isid': ofctl_utils.to_match_masked_int,
+ 'tunnel_id': ofctl_utils.to_match_masked_int,
+ 'ipv6_exthdr': ofctl_utils.to_match_masked_int,
+ 'pbb_uca': int,
+ 'tcp_flags': int,
+ 'actset_output': int,
+ 'packet_type': ofctl_utils.to_match_packet_type,
+ }
+
+ keys = {'dl_dst': 'eth_dst',
+ 'dl_src': 'eth_src',
+ 'dl_type': 'eth_type',
+ 'dl_vlan': 'vlan_vid',
+ 'nw_src': 'ipv4_src',
+ 'nw_dst': 'ipv4_dst',
+ 'nw_proto': 'ip_proto'}
+
+ if attrs.get('eth_type') == ether.ETH_TYPE_ARP:
+ if 'ipv4_src' in attrs and 'arp_spa' not in attrs:
+ attrs['arp_spa'] = attrs['ipv4_src']
+ del attrs['ipv4_src']
+ if 'ipv4_dst' in attrs and 'arp_tpa' not in attrs:
+ attrs['arp_tpa'] = attrs['ipv4_dst']
+ del attrs['ipv4_dst']
+
+ kwargs = {}
+ for key, value in attrs.items():
+ if key in keys:
+ # For old field name
+ key = keys[key]
+ if key in convert:
+ value = convert[key](value)
+ kwargs[key] = value
+ else:
+ LOG.error('Unknown match field: %s', key)
+
+ return dp.ofproto_parser.OFPMatch(**kwargs)
+
+
+def to_match_vid(value):
+ return ofctl_utils.to_match_vid(value, ofproto_v1_5.OFPVID_PRESENT)
+
+
+def match_to_str(ofmatch):
+ match = {}
+
+ ofmatch = ofmatch.to_jsondict()['OFPMatch']
+ ofmatch = ofmatch['oxm_fields']
+
+ for match_field in ofmatch:
+ key = match_field['OXMTlv']['field']
+ mask = match_field['OXMTlv']['mask']
+ value = match_field['OXMTlv']['value']
+ if key == 'vlan_vid':
+ value = ofctl_utils.match_vid_to_str(value, mask,
+ ofproto_v1_5.OFPVID_PRESENT)
+ elif key == 'in_port':
+ value = UTIL.ofp_port_to_user(value)
+ elif key == 'packet_type':
+ value = [value >> 16, value & 0xffff]
+ else:
+ if mask is not None:
+ value = str(value) + '/' + str(mask)
+ match.setdefault(key, value)
+
+ return match
+
+
+def wrap_dpid_dict(dp, value, to_user=True):
+ if to_user:
+ return {str(dp.id): value}
+
+ return {dp.id: value}
+
+
+def stats_to_str(ofstats):
+
+ stats = {}
+ ofstats = ofstats.to_jsondict()['OFPStats']
+ ofstats = ofstats['oxs_fields']
+
+ for s in ofstats:
+ key = s['OXSTlv']['field']
+ if key == 'duration':
+ value = {
+ 'duration_sec': s['OXSTlv']['value'][0],
+ 'duration_nsec': s['OXSTlv']['value'][1],
+ }
+ elif key == 'idle_time':
+ value = {
+ 'idle_time_sec': s['OXSTlv']['value'][0],
+ 'idle_time_nsec': s['OXSTlv']['value'][1],
+ }
+ else:
+ value = s['OXSTlv']['value']
+ stats.setdefault(key, value)
+
+ return stats
+
+
+def get_desc_stats(dp, waiters, to_user=True):
+ stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+ s = {}
+
+ for msg in msgs:
+ stats = msg.body
+ s = stats.to_jsondict()[stats.__class__.__name__]
+
+ return wrap_dpid_dict(dp, s, to_user)
+
+
+def get_queue_stats(dp, waiters, port_no=None, queue_id=None, to_user=True):
+ if port_no is None:
+ port_no = dp.ofproto.OFPP_ANY
+ else:
+ port_no = UTIL.ofp_port_from_user(port_no)
+ if queue_id is None:
+ queue_id = dp.ofproto.OFPQ_ALL
+ else:
+ queue_id = UTIL.ofp_queue_from_user(queue_id)
+
+ stats = dp.ofproto_parser.OFPQueueStatsRequest(
+ dp, 0, port_no, queue_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ desc = []
+ for msg in msgs:
+ stats = msg.body
+ for stat in stats:
+ s = stat.to_jsondict()[stat.__class__.__name__]
+ properties = []
+ for prop in stat.properties:
+ p = prop.to_jsondict()[prop.__class__.__name__]
+ if to_user:
+ t = UTIL.ofp_queue_stats_prop_type_to_user(prop.type)
+ p['type'] = t if t != p['type'] else 'UNKNOWN'
+ properties.append(p)
+ s['properties'] = properties
+ desc.append(s)
+
+ return wrap_dpid_dict(dp, desc, to_user)
+
+
+def get_queue_desc(dp, waiters, port_no=None, queue_id=None, to_user=True):
+ if port_no is None:
+ port_no = dp.ofproto.OFPP_ANY
+ else:
+ port_no = UTIL.ofp_port_from_user(port_no)
+ if queue_id is None:
+ queue_id = dp.ofproto.OFPQ_ALL
+ else:
+ queue_id = UTIL.ofp_queue_from_user(queue_id)
+
+ stats = dp.ofproto_parser.OFPQueueDescStatsRequest(
+ dp, 0, port_no, queue_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ configs = []
+ for msg in msgs:
+ for queue in msg.body:
+ q = queue.to_jsondict()[queue.__class__.__name__]
+ prop_list = []
+ for prop in queue.properties:
+ p = prop.to_jsondict()[prop.__class__.__name__]
+ if to_user:
+ t = UTIL.ofp_queue_desc_prop_type_to_user(prop.type)
+ p['type'] = t if t != prop.type else 'UNKNOWN'
+ prop_list.append(p)
+ q['properties'] = prop_list
+ configs.append(q)
+
+ return wrap_dpid_dict(dp, configs, to_user)
+
+
+def get_flow_desc_stats(dp, waiters, flow=None, to_user=True):
+ flow = flow if flow else {}
+ table_id = UTIL.ofp_table_from_user(
+ flow.get('table_id', dp.ofproto.OFPTT_ALL))
+ flags = int(flow.get('flags', 0))
+ out_port = UTIL.ofp_port_from_user(
+ flow.get('out_port', dp.ofproto.OFPP_ANY))
+ out_group = UTIL.ofp_group_from_user(
+ flow.get('out_group', dp.ofproto.OFPG_ANY))
+ cookie = int(flow.get('cookie', 0))
+ cookie_mask = int(flow.get('cookie_mask', 0))
+ match = to_match(dp, flow.get('match', {}))
+
+ stats = dp.ofproto_parser.OFPFlowDescStatsRequest(
+ dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
+ match)
+
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ flows = []
+ for msg in msgs:
+ for stats in msg.body:
+ s = stats.to_jsondict()[stats.__class__.__name__]
+ s['instructions'] = instructions_to_str(stats.instructions)
+ s['stats'] = stats_to_str(stats.stats)
+ s['match'] = match_to_str(stats.match)
+ flows.append(s)
+
+ return wrap_dpid_dict(dp, flows, to_user)
+
+
+def get_flow_stats(dp, waiters, flow=None, to_user=True):
+ flow = flow if flow else {}
+ table_id = UTIL.ofp_table_from_user(
+ flow.get('table_id', dp.ofproto.OFPTT_ALL))
+ flags = int(flow.get('flags', 0))
+ out_port = UTIL.ofp_port_from_user(
+ flow.get('out_port', dp.ofproto.OFPP_ANY))
+ out_group = UTIL.ofp_group_from_user(
+ flow.get('out_group', dp.ofproto.OFPG_ANY))
+ cookie = int(flow.get('cookie', 0))
+ cookie_mask = int(flow.get('cookie_mask', 0))
+ match = to_match(dp, flow.get('match', {}))
+
+ stats = dp.ofproto_parser.OFPFlowStatsRequest(
+ dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
+ match)
+
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ flows = []
+ for msg in msgs:
+ for stats in msg.body:
+ s = stats.to_jsondict()[stats.__class__.__name__]
+ s['stats'] = stats_to_str(stats.stats)
+ s['match'] = match_to_str(stats.match)
+ flows.append(s)
+
+ return wrap_dpid_dict(dp, flows, to_user)
+
+
+def get_aggregate_flow_stats(dp, waiters, flow=None, to_user=True):
+ flow = flow if flow else {}
+ table_id = UTIL.ofp_table_from_user(
+ flow.get('table_id', dp.ofproto.OFPTT_ALL))
+ flags = int(flow.get('flags', 0))
+ out_port = UTIL.ofp_port_from_user(
+ flow.get('out_port', dp.ofproto.OFPP_ANY))
+ out_group = UTIL.ofp_group_from_user(
+ flow.get('out_group', dp.ofproto.OFPG_ANY))
+ cookie = int(flow.get('cookie', 0))
+ cookie_mask = int(flow.get('cookie_mask', 0))
+ match = to_match(dp, flow.get('match', {}))
+
+ stats = dp.ofproto_parser.OFPAggregateStatsRequest(
+ dp, flags, table_id, out_port, out_group, cookie, cookie_mask,
+ match)
+
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ flows = []
+ for msg in msgs:
+ stats = msg.body
+ s = stats.to_jsondict()[stats.__class__.__name__]
+ s['stats'] = stats_to_str(stats.stats)
+ flows.append(s)
+
+ return wrap_dpid_dict(dp, flows, to_user)
+
+
+def get_table_stats(dp, waiters, to_user=True):
+ stats = dp.ofproto_parser.OFPTableStatsRequest(dp, 0)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ tables = []
+ for msg in msgs:
+ stats = msg.body
+ for stat in stats:
+ s = stat.to_jsondict()[stat.__class__.__name__]
+
+ if to_user:
+ s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
+
+ tables.append(s)
+
+ return wrap_dpid_dict(dp, tables, to_user)
+
+
+def get_table_features(dp, waiters, to_user=True):
+ stats = dp.ofproto_parser.OFPTableFeaturesStatsRequest(dp, 0, [])
+ msgs = []
+ ofproto = dp.ofproto
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ p_type_instructions = [ofproto.OFPTFPT_INSTRUCTIONS,
+ ofproto.OFPTFPT_INSTRUCTIONS_MISS]
+
+ p_type_next_tables = [ofproto.OFPTFPT_NEXT_TABLES,
+ ofproto.OFPTFPT_NEXT_TABLES_MISS,
+ ofproto.OFPTFPT_TABLE_SYNC_FROM]
+
+ p_type_actions = [ofproto.OFPTFPT_WRITE_ACTIONS,
+ ofproto.OFPTFPT_WRITE_ACTIONS_MISS,
+ ofproto.OFPTFPT_APPLY_ACTIONS,
+ ofproto.OFPTFPT_APPLY_ACTIONS_MISS]
+
+ p_type_packet = ofproto.OFPTFPT_PACKET_TYPES
+
+ p_type_oxms = [ofproto.OFPTFPT_MATCH,
+ ofproto.OFPTFPT_WILDCARDS,
+ ofproto.OFPTFPT_WRITE_SETFIELD,
+ ofproto.OFPTFPT_WRITE_SETFIELD_MISS,
+ ofproto.OFPTFPT_APPLY_SETFIELD,
+ ofproto.OFPTFPT_APPLY_SETFIELD_MISS,
+ ofproto.OFPTFPT_WRITE_COPYFIELD,
+ ofproto.OFPTFPT_WRITE_COPYFIELD_MISS,
+ ofproto.OFPTFPT_APPLY_COPYFIELD,
+ ofproto.OFPTFPT_APPLY_COPYFIELD_MISS]
+
+ p_type_experimenter = [ofproto.OFPTFPT_EXPERIMENTER,
+ ofproto.OFPTFPT_EXPERIMENTER_MISS]
+
+ tables = []
+ for msg in msgs:
+ stats = msg.body
+ for stat in stats:
+ s = stat.to_jsondict()[stat.__class__.__name__]
+ properties = []
+ for prop in stat.properties:
+ p = {}
+ t = UTIL.ofp_table_feature_prop_type_to_user(prop.type)
+ p['type'] = t if t != prop.type else 'UNKNOWN'
+ if prop.type in p_type_instructions:
+ instruction_ids = []
+ for id in prop.instruction_ids:
+ i = {'len': id.len,
+ 'type': id.type}
+ instruction_ids.append(i)
+ p['instruction_ids'] = instruction_ids
+ elif prop.type in p_type_next_tables:
+ table_ids = []
+ for id in prop.table_ids:
+ table_ids.append(id)
+ p['table_ids'] = table_ids
+ elif prop.type in p_type_actions:
+ action_ids = []
+ for id in prop.action_ids:
+ i = id.to_jsondict()[id.__class__.__name__]
+ action_ids.append(i)
+ p['action_ids'] = action_ids
+ elif prop.type in p_type_oxms:
+ oxm_ids = []
+ for id in prop.oxm_ids:
+ i = id.to_jsondict()[id.__class__.__name__]
+ oxm_ids.append(i)
+ p['oxm_ids'] = oxm_ids
+ elif prop.type == p_type_packet:
+ oxm_values = []
+ for val in prop.oxm_values:
+ i = {val[0]: val[1]}
+ oxm_values.append(i)
+ p['oxm_values'] = oxm_values
+ elif prop.type in p_type_experimenter:
+ pass
+ properties.append(p)
+ s['name'] = stat.name.decode('utf-8')
+ s['properties'] = properties
+
+ if to_user:
+ s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
+
+ tables.append(s)
+
+ return wrap_dpid_dict(dp, tables, to_user)
+
+
+def get_port_stats(dp, waiters, port_no=None, to_user=True):
+ if port_no is None:
+ port_no = dp.ofproto.OFPP_ANY
+ else:
+ port_no = UTIL.ofp_port_from_user(port_no)
+
+ stats = dp.ofproto_parser.OFPPortStatsRequest(dp, 0, port_no)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ ports = []
+ for msg in msgs:
+ for stats in msg.body:
+ s = stats.to_jsondict()[stats.__class__.__name__]
+ properties = []
+ for prop in stats.properties:
+ p = prop.to_jsondict()[prop.__class__.__name__]
+ t = UTIL.ofp_port_stats_prop_type_to_user(prop.type)
+ p['type'] = t if t != prop.type else 'UNKNOWN'
+ properties.append(p)
+ s['properties'] = properties
+
+ if to_user:
+ s['port_no'] = UTIL.ofp_port_to_user(stats.port_no)
+
+ ports.append(s)
+
+ return wrap_dpid_dict(dp, ports, to_user)
+
+
+def get_meter_stats(dp, waiters, meter_id=None, to_user=True):
+ if meter_id is None:
+ meter_id = dp.ofproto.OFPM_ALL
+ else:
+ meter_id = UTIL.ofp_meter_from_user(meter_id)
+
+ stats = dp.ofproto_parser.OFPMeterStatsRequest(
+ dp, 0, meter_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ meters = []
+ for msg in msgs:
+ for stats in msg.body:
+ s = stats.to_jsondict()[stats.__class__.__name__]
+ bands = []
+ for band in stats.band_stats:
+ b = band.to_jsondict()[band.__class__.__name__]
+ bands.append(b)
+ s['band_stats'] = bands
+
+ if to_user:
+ s['meter_id'] = UTIL.ofp_meter_to_user(stats.meter_id)
+
+ meters.append(s)
+
+ return wrap_dpid_dict(dp, meters, to_user)
+
+
+def get_meter_features(dp, waiters, to_user=True):
+ ofp = dp.ofproto
+ type_convert = {ofp.OFPMBT_DROP: 'DROP',
+ ofp.OFPMBT_DSCP_REMARK: 'DSCP_REMARK'}
+
+ capa_convert = {ofp.OFPMF_KBPS: 'KBPS',
+ ofp.OFPMF_PKTPS: 'PKTPS',
+ ofp.OFPMF_BURST: 'BURST',
+ ofp.OFPMF_STATS: 'STATS'}
+
+ stats = dp.ofproto_parser.OFPMeterFeaturesStatsRequest(dp, 0)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ features = []
+ for msg in msgs:
+ for feature in msg.body:
+ band_types = []
+ for k, v in type_convert.items():
+ if (1 << k) & feature.band_types:
+
+ if to_user:
+ band_types.append(v)
+
+ else:
+ band_types.append(k)
+
+ capabilities = []
+ for k, v in sorted(capa_convert.items()):
+ if k & feature.capabilities:
+
+ if to_user:
+ capabilities.append(v)
+
+ else:
+ capabilities.append(k)
+
+ f = {'max_meter': feature.max_meter,
+ 'band_types': band_types,
+ 'capabilities': capabilities,
+ 'max_bands': feature.max_bands,
+ 'max_color': feature.max_color}
+ features.append(f)
+
+ return wrap_dpid_dict(dp, features, to_user)
+
+
+def get_meter_desc(dp, waiters, meter_id=None, to_user=True):
+ flags = {dp.ofproto.OFPMF_KBPS: 'KBPS',
+ dp.ofproto.OFPMF_PKTPS: 'PKTPS',
+ dp.ofproto.OFPMF_BURST: 'BURST',
+ dp.ofproto.OFPMF_STATS: 'STATS'}
+
+ if meter_id is None:
+ meter_id = dp.ofproto.OFPM_ALL
+ else:
+ meter_id = UTIL.ofp_meter_from_user(meter_id)
+
+ stats = dp.ofproto_parser.OFPMeterDescStatsRequest(
+ dp, 0, meter_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ configs = []
+ for msg in msgs:
+ for config in msg.body:
+ c = config.to_jsondict()[config.__class__.__name__]
+ bands = []
+ for band in config.bands:
+ b = band.to_jsondict()[band.__class__.__name__]
+
+ if to_user:
+ t = UTIL.ofp_meter_band_type_to_user(band.type)
+ b['type'] = t if t != band.type else 'UNKNOWN'
+
+ bands.append(b)
+ c_flags = []
+ for k, v in sorted(flags.items()):
+ if k & config.flags:
+ if to_user:
+ c_flags.append(v)
+
+ else:
+ c_flags.append(k)
+
+ c['flags'] = c_flags
+ c['bands'] = bands
+
+ if to_user:
+ c['meter_id'] = UTIL.ofp_meter_to_user(config.meter_id)
+
+ configs.append(c)
+
+ return wrap_dpid_dict(dp, configs, to_user)
+
+
+def get_group_stats(dp, waiters, group_id=None, to_user=True):
+ if group_id is None:
+ group_id = dp.ofproto.OFPG_ALL
+ else:
+ group_id = UTIL.ofp_group_from_user(group_id)
+
+ stats = dp.ofproto_parser.OFPGroupStatsRequest(
+ dp, 0, group_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ groups = []
+ for msg in msgs:
+ for stats in msg.body:
+ g = stats.to_jsondict()[stats.__class__.__name__]
+ bucket_stats = []
+ for bucket_stat in stats.bucket_stats:
+ c = bucket_stat.to_jsondict()[bucket_stat.__class__.__name__]
+ bucket_stats.append(c)
+ g['bucket_stats'] = bucket_stats
+
+ if to_user:
+ g['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
+
+ groups.append(g)
+
+ return wrap_dpid_dict(dp, groups, to_user)
+
+
+def get_group_features(dp, waiters, to_user=True):
+
+ ofp = dp.ofproto
+ type_convert = {ofp.OFPGT_ALL: 'ALL',
+ ofp.OFPGT_SELECT: 'SELECT',
+ ofp.OFPGT_INDIRECT: 'INDIRECT',
+ ofp.OFPGT_FF: 'FF'}
+ cap_convert = {ofp.OFPGFC_SELECT_WEIGHT: 'SELECT_WEIGHT',
+ ofp.OFPGFC_SELECT_LIVENESS: 'SELECT_LIVENESS',
+ ofp.OFPGFC_CHAINING: 'CHAINING',
+ ofp.OFPGFC_CHAINING_CHECKS: 'CHAINING_CHECKS'}
+ act_convert = {ofp.OFPAT_OUTPUT: 'OUTPUT',
+ ofp.OFPAT_COPY_TTL_OUT: 'COPY_TTL_OUT',
+ ofp.OFPAT_COPY_TTL_IN: 'COPY_TTL_IN',
+ ofp.OFPAT_SET_MPLS_TTL: 'SET_MPLS_TTL',
+ ofp.OFPAT_DEC_MPLS_TTL: 'DEC_MPLS_TTL',
+ ofp.OFPAT_PUSH_VLAN: 'PUSH_VLAN',
+ ofp.OFPAT_POP_VLAN: 'POP_VLAN',
+ ofp.OFPAT_PUSH_MPLS: 'PUSH_MPLS',
+ ofp.OFPAT_POP_MPLS: 'POP_MPLS',
+ ofp.OFPAT_SET_QUEUE: 'SET_QUEUE',
+ ofp.OFPAT_GROUP: 'GROUP',
+ ofp.OFPAT_SET_NW_TTL: 'SET_NW_TTL',
+ ofp.OFPAT_DEC_NW_TTL: 'DEC_NW_TTL',
+ ofp.OFPAT_SET_FIELD: 'SET_FIELD',
+ ofp.OFPAT_PUSH_PBB: 'PUSH_PBB',
+ ofp.OFPAT_POP_PBB: 'POP_PBB',
+ ofp.OFPAT_COPY_FIELD: 'COPY_FIELD',
+ ofp.OFPAT_METER: 'METER',
+ ofp.OFPAT_EXPERIMENTER: 'EXPERIMENTER',
+ }
+
+ stats = dp.ofproto_parser.OFPGroupFeaturesStatsRequest(dp, 0)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ features = []
+ for msg in msgs:
+ feature = msg.body
+ types = []
+ for k, v in type_convert.items():
+ if (1 << k) & feature.types:
+ if to_user:
+ types.append(v)
+
+ else:
+ types.append(k)
+
+ capabilities = []
+ for k, v in cap_convert.items():
+ if k & feature.capabilities:
+ if to_user:
+ capabilities.append(v)
+
+ else:
+ capabilities.append(k)
+
+ if to_user:
+ max_groups = []
+ for k, v in type_convert.items():
+ max_groups.append({v: feature.max_groups[k]})
+
+ else:
+ max_groups = feature.max_groups
+
+ actions = []
+ for k1, v1 in type_convert.items():
+ acts = []
+ for k2, v2 in act_convert.items():
+ if (1 << k2) & feature.actions[k1]:
+ if to_user:
+ acts.append(v2)
+
+ else:
+ acts.append(k2)
+
+ if to_user:
+ actions.append({v1: acts})
+
+ else:
+ actions.append({k1: acts})
+
+ f = {'types': types,
+ 'capabilities': capabilities,
+ 'max_groups': max_groups,
+ 'actions': actions}
+ features.append(f)
+
+ return wrap_dpid_dict(dp, features, to_user)
+
+
+def get_group_desc(dp, waiters, group_id=None, to_user=True):
+ if group_id is None:
+ group_id = dp.ofproto.OFPG_ALL
+ else:
+ group_id = UTIL.ofp_group_from_user(group_id)
+
+ stats = dp.ofproto_parser.OFPGroupDescStatsRequest(dp, 0, group_id)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ descs = []
+ for msg in msgs:
+ for stats in msg.body:
+ d = stats.to_jsondict()[stats.__class__.__name__]
+ buckets = []
+ for bucket in stats.buckets:
+ b = bucket.to_jsondict()[bucket.__class__.__name__]
+ actions = []
+ for action in bucket.actions:
+ if to_user:
+ actions.append(action_to_str(action))
+
+ else:
+ actions.append(action)
+ properties = []
+ for prop in bucket.properties:
+ p = prop.to_jsondict()[prop.__class__.__name__]
+ t = UTIL.ofp_group_bucket_prop_type_to_user(prop.type)
+ p['type'] = t if t != prop.type else 'UNKNOWN'
+ properties.append(p)
+ b['actions'] = actions
+ b['properties'] = properties
+ buckets.append(b)
+
+ d['buckets'] = buckets
+ if to_user:
+ d['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
+ t = UTIL.ofp_group_type_to_user(stats.type)
+ d['type'] = t if t != stats.type else 'UNKNOWN'
+
+ descs.append(d)
+
+ return wrap_dpid_dict(dp, descs, to_user)
+
+
+def get_port_desc(dp, waiters, port_no=None, to_user=True):
+ if port_no is None:
+ port_no = dp.ofproto.OFPP_ANY
+ else:
+ port_no = UTIL.ofp_port_from_user(port_no)
+
+ stats = dp.ofproto_parser.OFPPortDescStatsRequest(dp, 0, port_no)
+ msgs = []
+ ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
+
+ descs = []
+
+ for msg in msgs:
+ stats = msg.body
+ for stat in stats:
+ d = stat.to_jsondict()[stat.__class__.__name__]
+ properties = []
+ for prop in stat.properties:
+ p = prop.to_jsondict()[prop.__class__.__name__]
+
+ if to_user:
+ t = UTIL.ofp_port_desc_prop_type_to_user(prop.type)
+ p['type'] = t if t != prop.type else 'UNKNOWN'
+
+ properties.append(p)
+ d['name'] = stat.name.decode('utf-8')
+ d['properties'] = properties
+
+ if to_user:
+ d['port_no'] = UTIL.ofp_port_to_user(stat.port_no)
+
+ descs.append(d)
+
+ return wrap_dpid_dict(dp, descs, to_user)
+
+
+def mod_flow_entry(dp, flow, cmd):
+ cookie = int(flow.get('cookie', 0))
+ cookie_mask = int(flow.get('cookie_mask', 0))
+ table_id = UTIL.ofp_table_from_user(flow.get('table_id', 0))
+ idle_timeout = int(flow.get('idle_timeout', 0))
+ hard_timeout = int(flow.get('hard_timeout', 0))
+ priority = int(flow.get('priority', 0))
+ buffer_id = UTIL.ofp_buffer_from_user(
+ flow.get('buffer_id', dp.ofproto.OFP_NO_BUFFER))
+ out_port = UTIL.ofp_port_from_user(
+ flow.get('out_port', dp.ofproto.OFPP_ANY))
+ out_group = UTIL.ofp_group_from_user(
+ flow.get('out_group', dp.ofproto.OFPG_ANY))
+ importance = int(flow.get('importance', 0))
+ flags = int(flow.get('flags', 0))
+ match = to_match(dp, flow.get('match', {}))
+ inst = to_instructions(dp, flow.get('instructions', []))
+
+ flow_mod = dp.ofproto_parser.OFPFlowMod(
+ dp, cookie, cookie_mask, table_id, cmd, idle_timeout,
+ hard_timeout, priority, buffer_id, out_port, out_group,
+ importance, flags, match, inst)
+
+ ofctl_utils.send_msg(dp, flow_mod, LOG)
+
+
+def mod_meter_entry(dp, meter, cmd):
+ flags = 0
+ if 'flags' in meter:
+ meter_flags = meter['flags']
+ if not isinstance(meter_flags, list):
+ meter_flags = [meter_flags]
+ for flag in meter_flags:
+ t = UTIL.ofp_meter_flags_from_user(flag)
+ f = t if t != flag else None
+ if f is None:
+ LOG.error('Unknown meter flag: %s', flag)
+ continue
+ flags |= f
+
+ meter_id = UTIL.ofp_meter_from_user(meter.get('meter_id', 0))
+
+ bands = []
+ for band in meter.get('bands', []):
+ band_type = band.get('type')
+ rate = int(band.get('rate', 0))
+ burst_size = int(band.get('burst_size', 0))
+ if band_type == 'DROP':
+ bands.append(
+ dp.ofproto_parser.OFPMeterBandDrop(rate, burst_size))
+ elif band_type == 'DSCP_REMARK':
+ prec_level = int(band.get('prec_level', 0))
+ bands.append(
+ dp.ofproto_parser.OFPMeterBandDscpRemark(
+ rate, burst_size, prec_level))
+ elif band_type == 'EXPERIMENTER':
+ experimenter = int(band.get('experimenter', 0))
+ bands.append(
+ dp.ofproto_parser.OFPMeterBandExperimenter(
+ rate, burst_size, experimenter))
+ else:
+ LOG.error('Unknown band type: %s', band_type)
+
+ meter_mod = dp.ofproto_parser.OFPMeterMod(
+ dp, cmd, flags, meter_id, bands)
+
+ ofctl_utils.send_msg(dp, meter_mod, LOG)
+
+
+def mod_group_entry(dp, group, cmd):
+ ofp = dp.ofproto
+ parser = dp.ofproto_parser
+
+ group_type = str(group.get('type', 'ALL'))
+ t = UTIL.ofp_group_type_from_user(group_type)
+ group_type = t if t != group_type else None
+ if group_type is None:
+ LOG.error('Unknown group type: %s', group.get('type'))
+
+ group_id = UTIL.ofp_group_from_user(group.get('group_id', 0))
+ command_bucket_id = int(group.get('command_bucket_id', 0))
+
+ # Note:
+ # The list of group property types that are currently defined
+ # are only OFPGPT_EXPERIMENTER(Experimenter defined).
+ properties = []
+
+ buckets = []
+ for bucket in group.get('buckets', []):
+
+ # get bucket_id in buckets
+ bucket_id = int(bucket.get('bucket_id', 0))
+
+ # get actions in buckets
+ bucket_actions = []
+ for dic in bucket.get('actions', []):
+ action = to_action(dp, dic)
+ if action is not None:
+ bucket_actions.append(action)
+
+ # get properties in buckets
+ bucket_properties = []
+ for p in bucket.get('properties', []):
+ group_bp_type = str(p.get('type', 'WEIGHT'))
+ t = UTIL.ofp_group_bucket_prop_type_from_user(group_bp_type)
+ group_bp_type = t if t != group_bp_type else ofp.OFPGBPT_WEIGHT
+
+ if group_bp_type == ofp.OFPGBPT_WEIGHT:
+ weight = int(p.get('weight', 0))
+ bucket_properties.append(
+ parser.OFPGroupBucketPropWeight(
+ type_=group_bp_type, weight=weight))
+ elif group_bp_type == ofp.OFPGBPT_WATCH_PORT:
+ watch_port = int(p.get('watch', dp.ofproto.OFPP_ANY))
+ bucket_properties.append(
+ parser.OFPGroupBucketPropWatch(
+ type_=group_bp_type, watch=watch_port))
+ elif group_bp_type == ofp.OFPGBPT_WATCH_GROUP:
+ watch_group = int(p.get('watch', dp.ofproto.OFPG_ANY))
+ bucket_properties.append(
+ parser.OFPGroupBucketPropWatch(
+ type_=group_bp_type, watch=watch_group))
+ elif group_bp_type == ofp.OFPGBPT_EXPERIMENTER:
+ experimenter = p.get('experimenter', 0)
+ exp_type = p.get('exp_type', 0)
+ data_type = p.get('data_type', 'ascii')
+ if data_type not in ['ascii', 'base64']:
+ LOG.error('Unknown data type: %s', data_type)
+ data = p.get('data', '')
+ if data_type == 'base64':
+ data = base64.b64decode(data)
+ bucket_properties.append(
+ parser.OFPGroupBucketPropExperimenter(
+ type_=group_bp_type, experimenter=experimenter,
+ exp_type=exp_type, data=data))
+ else:
+ LOG.error('Unknown group bucket prop type: %s', p['type'])
+
+ # create bucket
+ bucket = parser.OFPBucket(bucket_id=bucket_id,
+ actions=bucket_actions,
+ properties=bucket_properties)
+ buckets.append(bucket)
+
+ group_mod = parser.OFPGroupMod(dp, cmd, group_type, group_id,
+ command_bucket_id, buckets,
+ properties)
+
+ ofctl_utils.send_msg(dp, group_mod, LOG)
+
+
+def mod_port_behavior(dp, port_config):
+ ofp = dp.ofproto
+ parser = dp.ofproto_parser
+ port_no = UTIL.ofp_port_from_user(port_config.get('port_no', 0))
+ hw_addr = str(port_config.get('hw_addr'))
+ config = int(port_config.get('config', 0))
+ mask = int(port_config.get('mask', 0))
+ properties = port_config.get('properties')
+
+ prop = []
+ for p in properties:
+ type_ = UTIL.ofp_port_mod_prop_type_from_user(p['type'])
+ length = None
+ if type_ == ofp.OFPPDPT_ETHERNET:
+ advertise = UTIL.ofp_port_features_from_user(p['advertise'])
+ prop.append(
+ parser.OFPPortModPropEthernet(type_, length, advertise))
+ elif type_ == ofp.OFPPDPT_OPTICAL:
+ prop.append(
+ parser.OFPPortModPropOptical(
+ type_, length, p['configure'], p['freq_lmda'],
+ p['fl_offset'], p['grid_span'], p['tx_pwr']))
+ elif type_ == ofp.OFPPDPT_EXPERIMENTER:
+ prop.append(
+ parser.OFPPortModPropExperimenter(
+ type_, length, p['experimenter'], p['exp_type'],
+ p['data']))
+ else:
+ LOG.error('Unknown port desc prop type: %s', type_)
+
+ port_mod = dp.ofproto_parser.OFPPortMod(
+ dp, port_no, hw_addr, config, mask, prop)
+
+ ofctl_utils.send_msg(dp, port_mod, LOG)
+
+
+# NOTE(jkoelker) Alias common funcitons
+send_experimenter = ofctl_utils.send_experimenter