os-ken/ryu/lib/ofctl_v1_3.py
Michał Rzepka 8d93787a6c ryu/lib/ofctl_v1_3: port name decoding fix
The patch resolves issue experienced when decoding certain values of
name field in OFPMP_PORT_DESCRIPTION body. Non-decodable bytes are
replaced with utf-8 replacement character.

This issue was observed while retrieving OFPMP_PORT_DESC reply from
OpenFlow 1.3 compliant HP switch. One of ofp_struct structures
describing OFPP_LOCAL port has a name field with value 4f 46 50 50 5f 4c
4f 43 41 4c 00 81 ff ff ff ff that translates to OFPP_LOCAL.......
Attempt to decode the value, as in modified line, raises an exception
"UnicodeDecodeError: 'utf8' codec can't decode byte 0x81 in position 11:
invalid start byte". In the submitted patch, non-decodable characters
are replaced with utf-8 REPLACEMENT CHARACTER (U+FFFD), which is
sufficient for the get_port_desc method to work seamlessly. Similar
usages of str.decode method may be found in ofctl_v1_3, ofctl_v1_4,
ofctl_v1_5 and need to be fixed in the future.

Signed-off-by: Michal Rzepka <mrzepka@student.agh.edu.pl>
Reviewed-by: Iwase Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
2016-10-08 22:52:36 +09:00

1163 lines
40 KiB
Python

# Copyright (C) 2013 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 inet
from ryu.ofproto import ofproto_common
from ryu.ofproto import ofproto_v1_3
from ryu.ofproto import ofproto_v1_3_parser
from ryu.lib import ofctl_nicira_ext
from ryu.lib import ofctl_utils
LOG = logging.getLogger('ryu.lib.ofctl_v1_3')
DEFAULT_TIMEOUT = 1.0
UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_3)
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 to_actions(dp, acts):
inst = []
actions = []
ofp = dp.ofproto
parser = dp.ofproto_parser
for a in acts:
action = to_action(dp, a)
if action is not None:
actions.append(action)
else:
action_type = a.get('type')
if action_type == 'WRITE_ACTIONS':
write_actions = []
write_acts = a.get('actions')
for act in write_acts:
action = to_action(dp, act)
if action is not None:
write_actions.append(action)
else:
LOG.error('Unknown action type: %s', action_type)
if write_actions:
inst.append(
parser.OFPInstructionActions(ofp.OFPIT_WRITE_ACTIONS,
write_actions))
elif action_type == 'CLEAR_ACTIONS':
inst.append(
parser.OFPInstructionActions(ofp.OFPIT_CLEAR_ACTIONS, []))
elif action_type == 'GOTO_TABLE':
table_id = UTIL.ofp_table_from_user(a.get('table_id'))
inst.append(parser.OFPInstructionGotoTable(table_id))
elif action_type == 'WRITE_METADATA':
metadata = ofctl_utils.str_to_int(a.get('metadata'))
metadata_mask = (ofctl_utils.str_to_int(a['metadata_mask'])
if 'metadata_mask' in a
else parser.UINT64_MAX)
inst.append(
parser.OFPInstructionWriteMetadata(
metadata, metadata_mask))
elif action_type == 'METER':
meter_id = UTIL.ofp_meter_from_user(a.get('meter_id'))
inst.append(parser.OFPInstructionMeter(meter_id))
else:
LOG.error('Unknown action type: %s', action_type)
if actions:
inst.append(parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS,
actions))
return inst
def action_to_str(act):
action_type = act.cls_action_type
if action_type == ofproto_v1_3.OFPAT_OUTPUT:
port = UTIL.ofp_port_to_user(act.port)
buf = 'OUTPUT:' + str(port)
elif action_type == ofproto_v1_3.OFPAT_COPY_TTL_OUT:
buf = 'COPY_TTL_OUT'
elif action_type == ofproto_v1_3.OFPAT_COPY_TTL_IN:
buf = 'COPY_TTL_IN'
elif action_type == ofproto_v1_3.OFPAT_SET_MPLS_TTL:
buf = 'SET_MPLS_TTL:' + str(act.mpls_ttl)
elif action_type == ofproto_v1_3.OFPAT_DEC_MPLS_TTL:
buf = 'DEC_MPLS_TTL'
elif action_type == ofproto_v1_3.OFPAT_PUSH_VLAN:
buf = 'PUSH_VLAN:' + str(act.ethertype)
elif action_type == ofproto_v1_3.OFPAT_POP_VLAN:
buf = 'POP_VLAN'
elif action_type == ofproto_v1_3.OFPAT_PUSH_MPLS:
buf = 'PUSH_MPLS:' + str(act.ethertype)
elif action_type == ofproto_v1_3.OFPAT_POP_MPLS:
buf = 'POP_MPLS:' + str(act.ethertype)
elif action_type == ofproto_v1_3.OFPAT_SET_QUEUE:
queue_id = UTIL.ofp_queue_to_user(act.queue_id)
buf = 'SET_QUEUE:' + str(queue_id)
elif action_type == ofproto_v1_3.OFPAT_GROUP:
group_id = UTIL.ofp_group_to_user(act.group_id)
buf = 'GROUP:' + str(group_id)
elif action_type == ofproto_v1_3.OFPAT_SET_NW_TTL:
buf = 'SET_NW_TTL:' + str(act.nw_ttl)
elif action_type == ofproto_v1_3.OFPAT_DEC_NW_TTL:
buf = 'DEC_NW_TTL'
elif action_type == ofproto_v1_3.OFPAT_SET_FIELD:
buf = 'SET_FIELD: {%s:%s}' % (act.key, act.value)
elif action_type == ofproto_v1_3.OFPAT_PUSH_PBB:
buf = 'PUSH_PBB:' + str(act.ethertype)
elif action_type == ofproto_v1_3.OFPAT_POP_PBB:
buf = 'POP_PBB'
elif action_type == ofproto_v1_3.OFPAT_EXPERIMENTER:
if act.experimenter == ofproto_common.NX_EXPERIMENTER_ID:
try:
return ofctl_nicira_ext.action_to_str(act, action_to_str)
except Exception:
LOG.debug('Error parsing NX_ACTION(%s)',
act.__class__.__name__, exc_info=True)
data_str = base64.b64encode(act.data)
buf = 'EXPERIMENTER: {experimenter:%s, data:%s}' % \
(act.experimenter, data_str.decode('utf-8'))
else:
buf = 'UNKNOWN'
return buf
def actions_to_str(instructions):
actions = []
for instruction in instructions:
if isinstance(instruction,
ofproto_v1_3_parser.OFPInstructionActions):
if instruction.type == ofproto_v1_3.OFPIT_APPLY_ACTIONS:
for a in instruction.actions:
actions.append(action_to_str(a))
elif instruction.type == ofproto_v1_3.OFPIT_WRITE_ACTIONS:
write_actions = []
for a in instruction.actions:
write_actions.append(action_to_str(a))
if write_actions:
actions.append({'WRITE_ACTIONS': write_actions})
elif instruction.type == ofproto_v1_3.OFPIT_CLEAR_ACTIONS:
actions.append('CLEAR_ACTIONS')
else:
actions.append('UNKNOWN')
elif isinstance(instruction,
ofproto_v1_3_parser.OFPInstructionGotoTable):
table_id = UTIL.ofp_table_to_user(instruction.table_id)
buf = 'GOTO_TABLE:' + str(table_id)
actions.append(buf)
elif isinstance(instruction,
ofproto_v1_3_parser.OFPInstructionWriteMetadata):
buf = ('WRITE_METADATA:0x%x/0x%x' % (instruction.metadata,
instruction.metadata_mask)
if instruction.metadata_mask
else 'WRITE_METADATA:0x%x' % instruction.metadata)
actions.append(buf)
elif isinstance(instruction,
ofproto_v1_3_parser.OFPInstructionMeter):
meter_id = UTIL.ofp_meter_to_user(instruction.meter_id)
buf = 'METER:' + str(meter_id)
actions.append(buf)
else:
continue
return actions
def to_match(dp, attrs):
convert = {'in_port': UTIL.ofp_port_from_user,
'in_phy_port': int,
'metadata': ofctl_utils.to_match_masked_int,
'dl_dst': ofctl_utils.to_match_eth,
'dl_src': ofctl_utils.to_match_eth,
'eth_dst': ofctl_utils.to_match_eth,
'eth_src': ofctl_utils.to_match_eth,
'dl_type': int,
'eth_type': int,
'dl_vlan': to_match_vid,
'vlan_vid': to_match_vid,
'vlan_pcp': int,
'ip_dscp': int,
'ip_ecn': int,
'nw_proto': int,
'ip_proto': int,
'nw_src': ofctl_utils.to_match_ip,
'nw_dst': ofctl_utils.to_match_ip,
'ipv4_src': ofctl_utils.to_match_ip,
'ipv4_dst': ofctl_utils.to_match_ip,
'tp_src': int,
'tp_dst': int,
'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}
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('dl_type') == ether.ETH_TYPE_ARP or \
attrs.get('eth_type') == ether.ETH_TYPE_ARP:
if 'nw_src' in attrs and 'arp_spa' not in attrs:
attrs['arp_spa'] = attrs['nw_src']
del attrs['nw_src']
if 'nw_dst' in attrs and 'arp_tpa' not in attrs:
attrs['arp_tpa'] = attrs['nw_dst']
del attrs['nw_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)
if key == 'tp_src' or key == 'tp_dst':
# TCP/UDP port
conv = {inet.IPPROTO_TCP: {'tp_src': 'tcp_src',
'tp_dst': 'tcp_dst'},
inet.IPPROTO_UDP: {'tp_src': 'udp_src',
'tp_dst': 'udp_dst'}}
ip_proto = attrs.get('nw_proto', attrs.get('ip_proto', 0))
key = conv[ip_proto][key]
kwargs[key] = value
else:
# others
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_3.OFPVID_PRESENT)
def match_to_str(ofmatch):
keys = {'eth_src': 'dl_src',
'eth_dst': 'dl_dst',
'eth_type': 'dl_type',
'vlan_vid': 'dl_vlan',
'ipv4_src': 'nw_src',
'ipv4_dst': 'nw_dst',
'ip_proto': 'nw_proto',
'tcp_src': 'tp_src',
'tcp_dst': 'tp_dst',
'udp_src': 'tp_src',
'udp_dst': 'tp_dst'}
match = {}
ofmatch = ofmatch.to_jsondict()['OFPMatch']
ofmatch = ofmatch['oxm_fields']
for match_field in ofmatch:
key = match_field['OXMTlv']['field']
if key in keys:
key = keys[key]
mask = match_field['OXMTlv']['mask']
value = match_field['OXMTlv']['value']
if key == 'dl_vlan':
value = ofctl_utils.match_vid_to_str(value, mask,
ofproto_v1_3.OFPVID_PRESENT)
elif key == 'in_port':
value = UTIL.ofp_port_to_user(value)
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 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 = {'mfr_desc': stats.mfr_desc,
'hw_desc': stats.hw_desc,
'sw_desc': stats.sw_desc,
'serial_num': stats.serial_num,
'dp_desc': stats.dp_desc}
return wrap_dpid_dict(dp, s, to_user)
def get_queue_stats(dp, waiters, port=None, queue_id=None, to_user=True):
ofp = dp.ofproto
if port is None:
port = ofp.OFPP_ANY
else:
port = int(str(port), 0)
if queue_id is None:
queue_id = ofp.OFPQ_ALL
else:
queue_id = int(str(queue_id), 0)
stats = dp.ofproto_parser.OFPQueueStatsRequest(dp, 0, port,
queue_id)
msgs = []
ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
s = []
for msg in msgs:
stats = msg.body
for stat in stats:
s.append({'duration_nsec': stat.duration_nsec,
'duration_sec': stat.duration_sec,
'port_no': stat.port_no,
'queue_id': stat.queue_id,
'tx_bytes': stat.tx_bytes,
'tx_errors': stat.tx_errors,
'tx_packets': stat.tx_packets})
return wrap_dpid_dict(dp, s, to_user)
def get_queue_config(dp, waiters, port=None, to_user=True):
ofp = dp.ofproto
if port is None:
port = ofp.OFPP_ANY
else:
port = UTIL.ofp_port_from_user(int(str(port), 0))
stats = dp.ofproto_parser.OFPQueueGetConfigRequest(dp, port)
msgs = []
ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
prop_type = {dp.ofproto.OFPQT_MIN_RATE: 'MIN_RATE',
dp.ofproto.OFPQT_MAX_RATE: 'MAX_RATE',
dp.ofproto.OFPQT_EXPERIMENTER: 'EXPERIMENTER'}
configs = []
for config in msgs:
queue_list = []
for queue in config.queues:
prop_list = []
for prop in queue.properties:
p = {'property': prop_type.get(prop.property, 'UNKNOWN')}
if prop.property == dp.ofproto.OFPQT_MIN_RATE or \
prop.property == dp.ofproto.OFPQT_MAX_RATE:
p['rate'] = prop.rate
elif prop.property == dp.ofproto.OFPQT_EXPERIMENTER:
p['experimenter'] = prop.experimenter
p['data'] = prop.data
prop_list.append(p)
q = {'properties': prop_list}
if to_user:
q['port'] = UTIL.ofp_port_to_user(queue.port)
q['queue_id'] = UTIL.ofp_queue_to_user(queue.queue_id)
else:
q['port'] = queue.port
q['queue_id'] = queue.queue_id
queue_list.append(q)
c = {'queues': queue_list}
if to_user:
c['port'] = UTIL.ofp_port_to_user(config.port)
else:
c['port'] = config.port
configs.append(c)
return wrap_dpid_dict(dp, configs, 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 = {'priority': stats.priority,
'cookie': stats.cookie,
'idle_timeout': stats.idle_timeout,
'hard_timeout': stats.hard_timeout,
'byte_count': stats.byte_count,
'duration_sec': stats.duration_sec,
'duration_nsec': stats.duration_nsec,
'packet_count': stats.packet_count,
'length': stats.length,
'flags': stats.flags}
if to_user:
s['actions'] = actions_to_str(stats.instructions)
s['match'] = match_to_str(stats.match)
s['table_id'] = UTIL.ofp_table_to_user(stats.table_id)
else:
s['actions'] = stats.instructions
s['instructions'] = stats.instructions
s['match'] = stats.match
s['table_id'] = stats.table_id
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 = {'packet_count': stats.packet_count,
'byte_count': stats.byte_count,
'flow_count': stats.flow_count}
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 = {'active_count': stat.active_count,
'lookup_count': stat.lookup_count,
'matched_count': stat.matched_count}
if to_user:
s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
else:
s['table_id'] = 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)
prop_type = {ofproto.OFPTFPT_INSTRUCTIONS: 'INSTRUCTIONS',
ofproto.OFPTFPT_INSTRUCTIONS_MISS: 'INSTRUCTIONS_MISS',
ofproto.OFPTFPT_NEXT_TABLES: 'NEXT_TABLES',
ofproto.OFPTFPT_NEXT_TABLES_MISS: 'NEXT_TABLES_MISS',
ofproto.OFPTFPT_WRITE_ACTIONS: 'WRITE_ACTIONS',
ofproto.OFPTFPT_WRITE_ACTIONS_MISS: 'WRITE_ACTIONS_MISS',
ofproto.OFPTFPT_APPLY_ACTIONS: 'APPLY_ACTIONS',
ofproto.OFPTFPT_APPLY_ACTIONS_MISS: 'APPLY_ACTIONS_MISS',
ofproto.OFPTFPT_MATCH: 'MATCH',
ofproto.OFPTFPT_WILDCARDS: 'WILDCARDS',
ofproto.OFPTFPT_WRITE_SETFIELD: 'WRITE_SETFIELD',
ofproto.OFPTFPT_WRITE_SETFIELD_MISS: 'WRITE_SETFIELD_MISS',
ofproto.OFPTFPT_APPLY_SETFIELD: 'APPLY_SETFIELD',
ofproto.OFPTFPT_APPLY_SETFIELD_MISS: 'APPLY_SETFIELD_MISS',
ofproto.OFPTFPT_EXPERIMENTER: 'EXPERIMENTER',
ofproto.OFPTFPT_EXPERIMENTER_MISS: 'EXPERIMENTER_MISS'}
if not to_user:
prop_type = dict((k, k) for k in prop_type.keys())
p_type_instructions = [ofproto.OFPTFPT_INSTRUCTIONS,
ofproto.OFPTFPT_INSTRUCTIONS_MISS]
p_type_next_tables = [ofproto.OFPTFPT_NEXT_TABLES,
ofproto.OFPTFPT_NEXT_TABLES_MISS]
p_type_actions = [ofproto.OFPTFPT_WRITE_ACTIONS,
ofproto.OFPTFPT_WRITE_ACTIONS_MISS,
ofproto.OFPTFPT_APPLY_ACTIONS,
ofproto.OFPTFPT_APPLY_ACTIONS_MISS]
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]
p_type_experimenter = [ofproto.OFPTFPT_EXPERIMENTER,
ofproto.OFPTFPT_EXPERIMENTER_MISS]
tables = []
for msg in msgs:
stats = msg.body
for stat in stats:
properties = []
for prop in stat.properties:
p = {'type': prop_type.get(prop.type, 'UNKNOWN')}
if prop.type in p_type_instructions:
instruction_ids = []
for i in prop.instruction_ids:
inst = {'len': i.len,
'type': i.type}
instruction_ids.append(inst)
p['instruction_ids'] = instruction_ids
elif prop.type in p_type_next_tables:
table_ids = []
for i in prop.table_ids:
table_ids.append(i)
p['table_ids'] = table_ids
elif prop.type in p_type_actions:
action_ids = []
for i in prop.action_ids:
act = {'len': i.len,
'type': i.type}
action_ids.append(act)
p['action_ids'] = action_ids
elif prop.type in p_type_oxms:
oxm_ids = []
for i in prop.oxm_ids:
oxm = {'hasmask': i.hasmask,
'length': i.length,
'type': i.type}
oxm_ids.append(oxm)
p['oxm_ids'] = oxm_ids
elif prop.type in p_type_experimenter:
pass
properties.append(p)
s = {
'name': stat.name.decode('utf-8'),
'metadata_match': stat.metadata_match,
'metadata_write': stat.metadata_write,
'config': stat.config,
'max_entries': stat.max_entries,
'properties': properties,
}
if to_user:
s['table_id'] = UTIL.ofp_table_to_user(stat.table_id)
else:
s['table_id'] = stat.table_id
tables.append(s)
return wrap_dpid_dict(dp, tables, to_user)
def get_port_stats(dp, waiters, port=None, to_user=True):
if port is None:
port = dp.ofproto.OFPP_ANY
else:
port = int(str(port), 0)
stats = dp.ofproto_parser.OFPPortStatsRequest(
dp, 0, port)
msgs = []
ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
ports = []
for msg in msgs:
for stats in msg.body:
s = {'rx_packets': stats.rx_packets,
'tx_packets': stats.tx_packets,
'rx_bytes': stats.rx_bytes,
'tx_bytes': stats.tx_bytes,
'rx_dropped': stats.rx_dropped,
'tx_dropped': stats.tx_dropped,
'rx_errors': stats.rx_errors,
'tx_errors': stats.tx_errors,
'rx_frame_err': stats.rx_frame_err,
'rx_over_err': stats.rx_over_err,
'rx_crc_err': stats.rx_crc_err,
'collisions': stats.collisions,
'duration_sec': stats.duration_sec,
'duration_nsec': stats.duration_nsec}
if to_user:
s['port_no'] = UTIL.ofp_port_to_user(stats.port_no)
else:
s['port_no'] = 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 = int(str(meter_id), 0)
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:
bands = []
for band in stats.band_stats:
b = {'packet_band_count': band.packet_band_count,
'byte_band_count': band.byte_band_count}
bands.append(b)
s = {'len': stats.len,
'flow_count': stats.flow_count,
'packet_in_count': stats.packet_in_count,
'byte_in_count': stats.byte_in_count,
'duration_sec': stats.duration_sec,
'duration_nsec': stats.duration_nsec,
'band_stats': bands}
if to_user:
s['meter_id'] = UTIL.ofp_meter_to_user(stats.meter_id)
else:
s['meter_id'] = 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_config(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'}
band_type = {dp.ofproto.OFPMBT_DROP: 'DROP',
dp.ofproto.OFPMBT_DSCP_REMARK: 'DSCP_REMARK',
dp.ofproto.OFPMBT_EXPERIMENTER: 'EXPERIMENTER'}
if meter_id is None:
meter_id = dp.ofproto.OFPM_ALL
else:
meter_id = int(str(meter_id), 0)
stats = dp.ofproto_parser.OFPMeterConfigStatsRequest(
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:
bands = []
for band in config.bands:
b = {'rate': band.rate,
'burst_size': band.burst_size}
if to_user:
b['type'] = band_type.get(band.type, '')
else:
b['type'] = band.type
if band.type == dp.ofproto.OFPMBT_DSCP_REMARK:
b['prec_level'] = band.prec_level
elif band.type == dp.ofproto.OFPMBT_EXPERIMENTER:
b['experimenter'] = band.experimenter
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,
'bands': bands}
if to_user:
c['meter_id'] = UTIL.ofp_meter_to_user(config.meter_id)
else:
c['meter_id'] = 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 = int(str(group_id), 0)
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:
bucket_stats = []
for bucket_stat in stats.bucket_stats:
c = {'packet_count': bucket_stat.packet_count,
'byte_count': bucket_stat.byte_count}
bucket_stats.append(c)
g = {'length': stats.length,
'ref_count': stats.ref_count,
'packet_count': stats.packet_count,
'byte_count': stats.byte_count,
'duration_sec': stats.duration_sec,
'duration_nsec': stats.duration_nsec,
'bucket_stats': bucket_stats}
if to_user:
g['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
else:
g['group_id'] = 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'}
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, to_user=True):
type_convert = {dp.ofproto.OFPGT_ALL: 'ALL',
dp.ofproto.OFPGT_SELECT: 'SELECT',
dp.ofproto.OFPGT_INDIRECT: 'INDIRECT',
dp.ofproto.OFPGT_FF: 'FF'}
stats = dp.ofproto_parser.OFPGroupDescStatsRequest(dp, 0)
msgs = []
ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
descs = []
for msg in msgs:
for stats in msg.body:
buckets = []
for bucket in stats.buckets:
actions = []
for action in bucket.actions:
if to_user:
actions.append(action_to_str(action))
else:
actions.append(action)
b = {'weight': bucket.weight,
'watch_port': bucket.watch_port,
'watch_group': bucket.watch_group,
'actions': actions}
buckets.append(b)
d = {'buckets': buckets}
if to_user:
d['group_id'] = UTIL.ofp_group_to_user(stats.group_id)
d['type'] = type_convert.get(stats.type)
else:
d['group_id'] = stats.group_id
d['type'] = stats.type
descs.append(d)
return wrap_dpid_dict(dp, descs, to_user)
def get_port_desc(dp, waiters, to_user=True):
stats = dp.ofproto_parser.OFPPortDescStatsRequest(dp, 0)
msgs = []
ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG)
descs = []
for msg in msgs:
stats = msg.body
for stat in stats:
d = {'hw_addr': stat.hw_addr,
'name': stat.name.decode('utf-8', errors='replace'),
'config': stat.config,
'state': stat.state,
'curr': stat.curr,
'advertised': stat.advertised,
'supported': stat.supported,
'peer': stat.peer,
'curr_speed': stat.curr_speed,
'max_speed': stat.max_speed}
if to_user:
d['port_no'] = UTIL.ofp_port_to_user(stat.port_no)
else:
d['port_no'] = 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))
flags = int(flow.get('flags', 0))
match = to_match(dp, flow.get('match', {}))
inst = to_actions(dp, flow.get('actions', []))
flow_mod = dp.ofproto_parser.OFPFlowMod(
dp, cookie, cookie_mask, table_id, cmd, idle_timeout,
hard_timeout, priority, buffer_id, out_port, out_group,
flags, match, inst)
ofctl_utils.send_msg(dp, flow_mod, LOG)
def mod_meter_entry(dp, meter, cmd):
flags_convert = {'KBPS': dp.ofproto.OFPMF_KBPS,
'PKTPS': dp.ofproto.OFPMF_PKTPS,
'BURST': dp.ofproto.OFPMF_BURST,
'STATS': dp.ofproto.OFPMF_STATS}
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:
if flag not in flags_convert:
LOG.error('Unknown meter flag: %s', flag)
continue
flags |= flags_convert.get(flag)
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):
type_convert = {'ALL': dp.ofproto.OFPGT_ALL,
'SELECT': dp.ofproto.OFPGT_SELECT,
'INDIRECT': dp.ofproto.OFPGT_INDIRECT,
'FF': dp.ofproto.OFPGT_FF}
type_ = type_convert.get(group.get('type', 'ALL'))
if type_ is None:
LOG.error('Unknown group type: %s', group.get('type'))
group_id = UTIL.ofp_group_from_user(group.get('group_id', 0))
buckets = []
for bucket in group.get('buckets', []):
weight = int(bucket.get('weight', 0))
watch_port = int(bucket.get('watch_port', dp.ofproto.OFPP_ANY))
watch_group = int(bucket.get('watch_group', dp.ofproto.OFPG_ANY))
actions = []
for dic in bucket.get('actions', []):
action = to_action(dp, dic)
if action is not None:
actions.append(action)
buckets.append(dp.ofproto_parser.OFPBucket(
weight, watch_port, watch_group, actions))
group_mod = dp.ofproto_parser.OFPGroupMod(
dp, cmd, type_, group_id, buckets)
ofctl_utils.send_msg(dp, group_mod, LOG)
def mod_port_behavior(dp, port_config):
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))
advertise = int(port_config.get('advertise'))
port_mod = dp.ofproto_parser.OFPPortMod(
dp, port_no, hw_addr, config, mask, advertise)
ofctl_utils.send_msg(dp, port_mod, LOG)
def set_role(dp, role):
r = UTIL.ofp_role_from_user(role.get('role', dp.ofproto.OFPCR_ROLE_EQUAL))
role_request = dp.ofproto_parser.OFPRoleRequest(dp, r, 0)
ofctl_utils.send_msg(dp, role_request, LOG)
# NOTE(jkoelker) Alias common funcitons
send_experimenter = ofctl_utils.send_experimenter