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