# 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) str_to_int = ofctl_utils.str_to_int 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 = str_to_int(i.get('table_id')) instructions.append(parser.OFPInstructionGotoTable(table_id)) elif inst_type == 'WRITE_METADATA': metadata = str_to_int(i.get('metadata')) metadata_mask = (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': str_to_int, 'metadata': ofctl_utils.to_match_masked_int, 'eth_dst': ofctl_utils.to_match_eth, 'eth_src': ofctl_utils.to_match_eth, 'eth_type': str_to_int, 'vlan_vid': to_match_vid, 'vlan_pcp': str_to_int, 'ip_dscp': str_to_int, 'ip_ecn': str_to_int, 'ip_proto': str_to_int, 'ipv4_src': ofctl_utils.to_match_ip, 'ipv4_dst': ofctl_utils.to_match_ip, 'tcp_src': str_to_int, 'tcp_dst': str_to_int, 'udp_src': str_to_int, 'udp_dst': str_to_int, 'sctp_src': str_to_int, 'sctp_dst': str_to_int, 'icmpv4_type': str_to_int, 'icmpv4_code': str_to_int, 'arp_op': str_to_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': str_to_int, 'icmpv6_type': str_to_int, 'icmpv6_code': str_to_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': str_to_int, 'mpls_tc': str_to_int, 'mpls_bos': str_to_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': str_to_int, 'tcp_flags': str_to_int, 'actset_output': str_to_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 = match_vid_to_str(value, mask) 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 match_vid_to_str(value, mask): return ofctl_utils.match_vid_to_str( value, mask, ofproto_v1_5.OFPVID_PRESENT) 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 = str_to_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 = str_to_int(flow.get('cookie', 0)) cookie_mask = str_to_int(flow.get('cookie_mask', 0)) match = to_match(dp, flow.get('match', {})) # Note: OpenFlow does not allow to filter flow entries by priority, # but for efficiency, ofctl provides the way to do it. priority = str_to_int(flow.get('priority', -1)) 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: if 0 <= priority != stats.priority: continue 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 = str_to_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 = str_to_int(flow.get('cookie', 0)) cookie_mask = str_to_int(flow.get('cookie_mask', 0)) match = to_match(dp, flow.get('match', {})) # Note: OpenFlow does not allow to filter flow entries by priority, # but for efficiency, ofctl provides the way to do it. priority = str_to_int(flow.get('priority', -1)) 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: if 0 <= priority != stats.priority: continue 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 = str_to_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 = str_to_int(flow.get('cookie', 0)) cookie_mask = str_to_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 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 = i.to_jsondict()[i.__class__.__name__] 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 = i.to_jsondict()[i.__class__.__name__] oxm_ids.append(oxm) 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 get_role(dp, waiters, to_user=True): return ofctl_utils.get_role(dp, waiters, to_user) def mod_flow_entry(dp, flow, cmd): cookie = str_to_int(flow.get('cookie', 0)) cookie_mask = str_to_int(flow.get('cookie_mask', 0)) table_id = UTIL.ofp_table_from_user(flow.get('table_id', 0)) idle_timeout = str_to_int(flow.get('idle_timeout', 0)) hard_timeout = str_to_int(flow.get('hard_timeout', 0)) priority = str_to_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 = str_to_int(flow.get('importance', 0)) flags = str_to_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 = str_to_int(band.get('rate', 0)) burst_size = str_to_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 = str_to_int(band.get('prec_level', 0)) bands.append( dp.ofproto_parser.OFPMeterBandDscpRemark( rate, burst_size, prec_level)) elif band_type == 'EXPERIMENTER': experimenter = str_to_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 = str_to_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 = str_to_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 = str_to_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 = str_to_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 = str_to_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 = str_to_int(port_config.get('config', 0)) mask = str_to_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) 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, None, 0) ofctl_utils.send_msg(dp, role_request, LOG) # NOTE(jkoelker) Alias common funcitons send_experimenter = ofctl_utils.send_experimenter