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 logging 17import netaddr 18 19from ryu.ofproto import ether 20from ryu.ofproto import inet 21from ryu.ofproto import ofproto_v1_2 22from ryu.ofproto import ofproto_v1_2_parser 23from ryu.lib import ofctl_utils 24 25 26LOG = logging.getLogger('ryu.lib.ofctl_v1_2') 27 28DEFAULT_TIMEOUT = 1.0 29 30UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_2) 31str_to_int = ofctl_utils.str_to_int 32 33 34def to_action(dp, dic): 35 ofp = dp.ofproto 36 parser = dp.ofproto_parser 37 action_type = dic.get('type') 38 return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL) 39 40 41def to_actions(dp, acts): 42 inst = [] 43 actions = [] 44 ofp = dp.ofproto 45 parser = dp.ofproto_parser 46 47 for a in acts: 48 action = to_action(dp, a) 49 if action is not None: 50 actions.append(action) 51 else: 52 action_type = a.get('type') 53 if action_type == 'WRITE_ACTIONS': 54 write_actions = [] 55 write_acts = a.get('actions') 56 for act in write_acts: 57 action = to_action(dp, act) 58 if action is not None: 59 write_actions.append(action) 60 else: 61 LOG.error('Unknown action type: %s', action_type) 62 if write_actions: 63 inst.append( 64 parser.OFPInstructionActions(ofp.OFPIT_WRITE_ACTIONS, 65 write_actions)) 66 elif action_type == 'CLEAR_ACTIONS': 67 inst.append( 68 parser.OFPInstructionActions(ofp.OFPIT_CLEAR_ACTIONS, [])) 69 elif action_type == 'GOTO_TABLE': 70 table_id = UTIL.ofp_table_from_user(a.get('table_id')) 71 inst.append(parser.OFPInstructionGotoTable(table_id)) 72 elif action_type == 'WRITE_METADATA': 73 metadata = str_to_int(a.get('metadata')) 74 metadata_mask = (str_to_int(a['metadata_mask']) 75 if 'metadata_mask' in a 76 else parser.UINT64_MAX) 77 inst.append( 78 parser.OFPInstructionWriteMetadata( 79 metadata, metadata_mask)) 80 else: 81 LOG.error('Unknown action type: %s', action_type) 82 83 if actions: 84 inst.append(parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, 85 actions)) 86 return inst 87 88 89def action_to_str(act): 90 action_type = act.cls_action_type 91 92 if action_type == ofproto_v1_2.OFPAT_OUTPUT: 93 port = UTIL.ofp_port_to_user(act.port) 94 buf = 'OUTPUT:' + str(port) 95 elif action_type == ofproto_v1_2.OFPAT_COPY_TTL_OUT: 96 buf = 'COPY_TTL_OUT' 97 elif action_type == ofproto_v1_2.OFPAT_COPY_TTL_IN: 98 buf = 'COPY_TTL_IN' 99 elif action_type == ofproto_v1_2.OFPAT_SET_MPLS_TTL: 100 buf = 'SET_MPLS_TTL:' + str(act.mpls_ttl) 101 elif action_type == ofproto_v1_2.OFPAT_DEC_MPLS_TTL: 102 buf = 'DEC_MPLS_TTL' 103 elif action_type == ofproto_v1_2.OFPAT_PUSH_VLAN: 104 buf = 'PUSH_VLAN:' + str(act.ethertype) 105 elif action_type == ofproto_v1_2.OFPAT_POP_VLAN: 106 buf = 'POP_VLAN' 107 elif action_type == ofproto_v1_2.OFPAT_PUSH_MPLS: 108 buf = 'PUSH_MPLS:' + str(act.ethertype) 109 elif action_type == ofproto_v1_2.OFPAT_POP_MPLS: 110 buf = 'POP_MPLS:' + str(act.ethertype) 111 elif action_type == ofproto_v1_2.OFPAT_SET_QUEUE: 112 queue_id = UTIL.ofp_queue_to_user(act.queue_id) 113 buf = 'SET_QUEUE:' + str(queue_id) 114 elif action_type == ofproto_v1_2.OFPAT_GROUP: 115 group_id = UTIL.ofp_group_to_user(act.group_id) 116 buf = 'GROUP:' + str(group_id) 117 elif action_type == ofproto_v1_2.OFPAT_SET_NW_TTL: 118 buf = 'SET_NW_TTL:' + str(act.nw_ttl) 119 elif action_type == ofproto_v1_2.OFPAT_DEC_NW_TTL: 120 buf = 'DEC_NW_TTL' 121 elif action_type == ofproto_v1_2.OFPAT_SET_FIELD: 122 buf = 'SET_FIELD: {%s:%s}' % (act.key, act.value) 123 else: 124 buf = 'UNKNOWN' 125 return buf 126 127 128def actions_to_str(instructions): 129 actions = [] 130 131 for instruction in instructions: 132 if isinstance(instruction, 133 ofproto_v1_2_parser.OFPInstructionActions): 134 if instruction.type == ofproto_v1_2.OFPIT_APPLY_ACTIONS: 135 for a in instruction.actions: 136 actions.append(action_to_str(a)) 137 elif instruction.type == ofproto_v1_2.OFPIT_WRITE_ACTIONS: 138 write_actions = [] 139 for a in instruction.actions: 140 write_actions.append(action_to_str(a)) 141 if write_actions: 142 actions.append({'WRITE_ACTIONS': write_actions}) 143 elif instruction.type == ofproto_v1_2.OFPIT_CLEAR_ACTIONS: 144 actions.append('CLEAR_ACTIONS') 145 else: 146 actions.append('UNKNOWN') 147 elif isinstance(instruction, 148 ofproto_v1_2_parser.OFPInstructionGotoTable): 149 table_id = UTIL.ofp_table_to_user(instruction.table_id) 150 buf = 'GOTO_TABLE:' + str(table_id) 151 actions.append(buf) 152 153 elif isinstance(instruction, 154 ofproto_v1_2_parser.OFPInstructionWriteMetadata): 155 buf = ('WRITE_METADATA:0x%x/0x%x' % (instruction.metadata, 156 instruction.metadata_mask) 157 if instruction.metadata_mask 158 else 'WRITE_METADATA:0x%x' % instruction.metadata) 159 actions.append(buf) 160 161 else: 162 continue 163 164 return actions 165 166 167def to_match(dp, attrs): 168 convert = {'in_port': UTIL.ofp_port_from_user, 169 'in_phy_port': str_to_int, 170 'metadata': ofctl_utils.to_match_masked_int, 171 'dl_dst': ofctl_utils.to_match_eth, 172 'dl_src': ofctl_utils.to_match_eth, 173 'eth_dst': ofctl_utils.to_match_eth, 174 'eth_src': ofctl_utils.to_match_eth, 175 'dl_type': str_to_int, 176 'eth_type': str_to_int, 177 'dl_vlan': to_match_vid, 178 'vlan_vid': to_match_vid, 179 'vlan_pcp': str_to_int, 180 'ip_dscp': str_to_int, 181 'ip_ecn': str_to_int, 182 'nw_proto': str_to_int, 183 'ip_proto': str_to_int, 184 'nw_src': ofctl_utils.to_match_ip, 185 'nw_dst': ofctl_utils.to_match_ip, 186 'ipv4_src': ofctl_utils.to_match_ip, 187 'ipv4_dst': ofctl_utils.to_match_ip, 188 'tp_src': str_to_int, 189 'tp_dst': str_to_int, 190 'tcp_src': str_to_int, 191 'tcp_dst': str_to_int, 192 'udp_src': str_to_int, 193 'udp_dst': str_to_int, 194 'sctp_src': str_to_int, 195 'sctp_dst': str_to_int, 196 'icmpv4_type': str_to_int, 197 'icmpv4_code': str_to_int, 198 'arp_op': str_to_int, 199 'arp_spa': ofctl_utils.to_match_ip, 200 'arp_tpa': ofctl_utils.to_match_ip, 201 'arp_sha': ofctl_utils.to_match_eth, 202 'arp_tha': ofctl_utils.to_match_eth, 203 'ipv6_src': ofctl_utils.to_match_ip, 204 'ipv6_dst': ofctl_utils.to_match_ip, 205 'ipv6_flabel': str_to_int, 206 'icmpv6_type': str_to_int, 207 'icmpv6_code': str_to_int, 208 'ipv6_nd_target': ofctl_utils.to_match_ip, 209 'ipv6_nd_sll': ofctl_utils.to_match_eth, 210 'ipv6_nd_tll': ofctl_utils.to_match_eth, 211 'mpls_label': str_to_int, 212 'mpls_tc': str_to_int} 213 214 keys = {'dl_dst': 'eth_dst', 215 'dl_src': 'eth_src', 216 'dl_type': 'eth_type', 217 'dl_vlan': 'vlan_vid', 218 'nw_src': 'ipv4_src', 219 'nw_dst': 'ipv4_dst', 220 'nw_proto': 'ip_proto'} 221 222 if attrs.get('dl_type') == ether.ETH_TYPE_ARP or \ 223 attrs.get('eth_type') == ether.ETH_TYPE_ARP: 224 if 'nw_src' in attrs and 'arp_spa' not in attrs: 225 attrs['arp_spa'] = attrs['nw_src'] 226 del attrs['nw_src'] 227 if 'nw_dst' in attrs and 'arp_tpa' not in attrs: 228 attrs['arp_tpa'] = attrs['nw_dst'] 229 del attrs['nw_dst'] 230 231 kwargs = {} 232 for key, value in attrs.items(): 233 if key in keys: 234 # For old field name 235 key = keys[key] 236 if key in convert: 237 value = convert[key](value) 238 if key == 'tp_src' or key == 'tp_dst': 239 # TCP/UDP port 240 conv = {inet.IPPROTO_TCP: {'tp_src': 'tcp_src', 241 'tp_dst': 'tcp_dst'}, 242 inet.IPPROTO_UDP: {'tp_src': 'udp_src', 243 'tp_dst': 'udp_dst'}} 244 ip_proto = attrs.get('nw_proto', attrs.get('ip_proto', 0)) 245 key = conv[ip_proto][key] 246 kwargs[key] = value 247 else: 248 # others 249 kwargs[key] = value 250 else: 251 LOG.error('Unknown match field: %s', key) 252 253 return dp.ofproto_parser.OFPMatch(**kwargs) 254 255 256def to_match_vid(value): 257 return ofctl_utils.to_match_vid(value, ofproto_v1_2.OFPVID_PRESENT) 258 259 260def match_to_str(ofmatch): 261 262 keys = {'eth_src': 'dl_src', 263 'eth_dst': 'dl_dst', 264 'eth_type': 'dl_type', 265 'vlan_vid': 'dl_vlan', 266 'ipv4_src': 'nw_src', 267 'ipv4_dst': 'nw_dst', 268 'ip_proto': 'nw_proto', 269 'tcp_src': 'tp_src', 270 'tcp_dst': 'tp_dst', 271 'udp_src': 'tp_src', 272 'udp_dst': 'tp_dst'} 273 274 match = {} 275 276 ofmatch = ofmatch.to_jsondict()['OFPMatch'] 277 ofmatch = ofmatch['oxm_fields'] 278 for match_field in ofmatch: 279 key = match_field['OXMTlv']['field'] 280 if key in keys: 281 key = keys[key] 282 mask = match_field['OXMTlv']['mask'] 283 value = match_field['OXMTlv']['value'] 284 if key == 'dl_vlan': 285 value = match_vid_to_str(value, mask) 286 elif key == 'in_port': 287 value = UTIL.ofp_port_to_user(value) 288 else: 289 if mask is not None: 290 value = str(value) + '/' + str(mask) 291 match.setdefault(key, value) 292 293 return match 294 295 296def match_vid_to_str(value, mask): 297 return ofctl_utils.match_vid_to_str( 298 value, mask, ofproto_v1_2.OFPVID_PRESENT) 299 300 301def get_desc_stats(dp, waiters): 302 stats = dp.ofproto_parser.OFPDescStatsRequest(dp) 303 msgs = [] 304 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 305 306 s = {} 307 for msg in msgs: 308 stats = msg.body 309 s = stats.to_jsondict()[stats.__class__.__name__] 310 311 return {str(dp.id): s} 312 313 314def get_queue_stats(dp, waiters, port=None, queue_id=None): 315 ofp = dp.ofproto 316 317 if port is None: 318 port = ofp.OFPP_ANY 319 else: 320 port = str_to_int(port) 321 322 if queue_id is None: 323 queue_id = ofp.OFPQ_ALL 324 else: 325 queue_id = str_to_int(queue_id) 326 327 stats = dp.ofproto_parser.OFPQueueStatsRequest(dp, port, 328 queue_id, 0) 329 msgs = [] 330 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 331 332 s = [] 333 for msg in msgs: 334 stats = msg.body 335 for stat in stats: 336 s.append({'port_no': stat.port_no, 337 'queue_id': stat.queue_id, 338 'tx_bytes': stat.tx_bytes, 339 'tx_errors': stat.tx_errors, 340 'tx_packets': stat.tx_packets}) 341 342 return {str(dp.id): s} 343 344 345def get_queue_config(dp, waiters, port=None): 346 ofp = dp.ofproto 347 if port is None: 348 port = ofp.OFPP_ANY 349 else: 350 port = UTIL.ofp_port_from_user(str_to_int(port)) 351 stats = dp.ofproto_parser.OFPQueueGetConfigRequest(dp, port) 352 msgs = [] 353 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 354 355 prop_type = { 356 dp.ofproto.OFPQT_MIN_RATE: 'MIN_RATE', 357 dp.ofproto.OFPQT_MAX_RATE: 'MAX_RATE', 358 dp.ofproto.OFPQT_EXPERIMENTER: 'EXPERIMENTER', 359 } 360 361 configs = [] 362 for config in msgs: 363 queue_list = [] 364 for queue in config.queues: 365 prop_list = [] 366 for prop in queue.properties: 367 p = {'property': prop_type.get(prop.property, 'UNKNOWN')} 368 if prop.property == dp.ofproto.OFPQT_MIN_RATE or \ 369 prop.property == dp.ofproto.OFPQT_MAX_RATE: 370 p['rate'] = prop.rate 371 elif prop.property == dp.ofproto.OFPQT_EXPERIMENTER: 372 p['experimenter'] = prop.experimenter 373 p['data'] = prop.data 374 prop_list.append(p) 375 q = {'port': UTIL.ofp_port_to_user(queue.port), 376 'properties': prop_list, 377 'queue_id': UTIL.ofp_queue_to_user(queue.queue_id)} 378 queue_list.append(q) 379 c = {'port': UTIL.ofp_port_to_user(config.port), 380 'queues': queue_list} 381 configs.append(c) 382 383 return {str(dp.id): configs} 384 385 386def get_flow_stats(dp, waiters, flow=None): 387 flow = flow if flow else {} 388 table_id = UTIL.ofp_table_from_user( 389 flow.get('table_id', dp.ofproto.OFPTT_ALL)) 390 out_port = UTIL.ofp_port_from_user( 391 flow.get('out_port', dp.ofproto.OFPP_ANY)) 392 out_group = UTIL.ofp_group_from_user( 393 flow.get('out_group', dp.ofproto.OFPG_ANY)) 394 cookie = str_to_int(flow.get('cookie', 0)) 395 cookie_mask = str_to_int(flow.get('cookie_mask', 0)) 396 match = to_match(dp, flow.get('match', {})) 397 # Note: OpenFlow does not allow to filter flow entries by priority, 398 # but for efficiency, ofctl provides the way to do it. 399 priority = str_to_int(flow.get('priority', -1)) 400 401 stats = dp.ofproto_parser.OFPFlowStatsRequest( 402 dp, table_id, out_port, out_group, cookie, cookie_mask, match) 403 404 msgs = [] 405 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 406 407 flows = [] 408 for msg in msgs: 409 for stats in msg.body: 410 if 0 <= priority != stats.priority: 411 continue 412 413 actions = actions_to_str(stats.instructions) 414 match = match_to_str(stats.match) 415 s = {'priority': stats.priority, 416 'cookie': stats.cookie, 417 'idle_timeout': stats.idle_timeout, 418 'hard_timeout': stats.hard_timeout, 419 'actions': actions, 420 'match': match, 421 'byte_count': stats.byte_count, 422 'duration_sec': stats.duration_sec, 423 'duration_nsec': stats.duration_nsec, 424 'packet_count': stats.packet_count, 425 'table_id': UTIL.ofp_table_to_user(stats.table_id), 426 'length': stats.length} 427 flows.append(s) 428 429 return {str(dp.id): flows} 430 431 432def get_aggregate_flow_stats(dp, waiters, flow=None): 433 flow = flow if flow else {} 434 table_id = UTIL.ofp_table_from_user( 435 flow.get('table_id', dp.ofproto.OFPTT_ALL)) 436 out_port = UTIL.ofp_port_from_user( 437 flow.get('out_port', dp.ofproto.OFPP_ANY)) 438 out_group = UTIL.ofp_group_from_user( 439 flow.get('out_group', dp.ofproto.OFPG_ANY)) 440 cookie = str_to_int(flow.get('cookie', 0)) 441 cookie_mask = str_to_int(flow.get('cookie_mask', 0)) 442 match = to_match(dp, flow.get('match', {})) 443 444 stats = dp.ofproto_parser.OFPAggregateStatsRequest( 445 dp, table_id, out_port, out_group, cookie, cookie_mask, match) 446 447 msgs = [] 448 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 449 450 flows = [] 451 for msg in msgs: 452 stats = msg.body 453 s = {'packet_count': stats.packet_count, 454 'byte_count': stats.byte_count, 455 'flow_count': stats.flow_count} 456 flows.append(s) 457 458 return {str(dp.id): flows} 459 460 461def get_table_stats(dp, waiters): 462 stats = dp.ofproto_parser.OFPTableStatsRequest(dp) 463 ofp = dp.ofproto 464 msgs = [] 465 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 466 467 oxm_type_convert = {ofp.OFPXMT_OFB_IN_PORT: 'IN_PORT', 468 ofp.OFPXMT_OFB_IN_PHY_PORT: 'IN_PHY_PORT', 469 ofp.OFPXMT_OFB_METADATA: 'METADATA', 470 ofp.OFPXMT_OFB_ETH_DST: 'ETH_DST', 471 ofp.OFPXMT_OFB_ETH_SRC: 'ETH_SRC', 472 ofp.OFPXMT_OFB_ETH_TYPE: 'ETH_TYPE', 473 ofp.OFPXMT_OFB_VLAN_VID: 'VLAN_VID', 474 ofp.OFPXMT_OFB_VLAN_PCP: 'VLAN_PCP', 475 ofp.OFPXMT_OFB_IP_DSCP: 'IP_DSCP', 476 ofp.OFPXMT_OFB_IP_ECN: 'IP_ECN', 477 ofp.OFPXMT_OFB_IP_PROTO: 'IP_PROTO', 478 ofp.OFPXMT_OFB_IPV4_SRC: 'IPV4_SRC', 479 ofp.OFPXMT_OFB_IPV4_DST: 'IPV4_DST', 480 ofp.OFPXMT_OFB_TCP_SRC: 'TCP_SRC', 481 ofp.OFPXMT_OFB_TCP_DST: 'TCP_DST', 482 ofp.OFPXMT_OFB_UDP_SRC: 'UDP_SRC', 483 ofp.OFPXMT_OFB_UDP_DST: 'UDP_DST', 484 ofp.OFPXMT_OFB_SCTP_SRC: 'SCTP_SRC', 485 ofp.OFPXMT_OFB_SCTP_DST: 'SCTP_DST', 486 ofp.OFPXMT_OFB_ICMPV4_TYPE: 'ICMPV4_TYPE', 487 ofp.OFPXMT_OFB_ICMPV4_CODE: 'ICMPV4_CODE', 488 ofp.OFPXMT_OFB_ARP_OP: 'ARP_OP', 489 ofp.OFPXMT_OFB_ARP_SPA: 'ARP_SPA', 490 ofp.OFPXMT_OFB_ARP_TPA: 'ARP_TPA', 491 ofp.OFPXMT_OFB_ARP_SHA: 'ARP_SHA', 492 ofp.OFPXMT_OFB_ARP_THA: 'ARP_THA', 493 ofp.OFPXMT_OFB_IPV6_SRC: 'IPV6_SRC', 494 ofp.OFPXMT_OFB_IPV6_DST: 'IPV6_DST', 495 ofp.OFPXMT_OFB_IPV6_FLABEL: 'IPV6_FLABEL', 496 ofp.OFPXMT_OFB_ICMPV6_TYPE: 'ICMPV6_TYPE', 497 ofp.OFPXMT_OFB_ICMPV6_CODE: 'ICMPV6_CODE', 498 ofp.OFPXMT_OFB_IPV6_ND_TARGET: 'IPV6_ND_TARGET', 499 ofp.OFPXMT_OFB_IPV6_ND_SLL: 'IPV6_ND_SLL', 500 ofp.OFPXMT_OFB_IPV6_ND_TLL: 'IPV6_ND_TLL', 501 ofp.OFPXMT_OFB_MPLS_LABEL: 'MPLS_LABEL', 502 ofp.OFPXMT_OFB_MPLS_TC: 'MPLS_TC'} 503 504 act_convert = {ofp.OFPAT_OUTPUT: 'OUTPUT', 505 ofp.OFPAT_COPY_TTL_OUT: 'COPY_TTL_OUT', 506 ofp.OFPAT_COPY_TTL_IN: 'COPY_TTL_IN', 507 ofp.OFPAT_SET_MPLS_TTL: 'SET_MPLS_TTL', 508 ofp.OFPAT_DEC_MPLS_TTL: 'DEC_MPLS_TTL', 509 ofp.OFPAT_PUSH_VLAN: 'PUSH_VLAN', 510 ofp.OFPAT_POP_VLAN: 'POP_VLAN', 511 ofp.OFPAT_PUSH_MPLS: 'PUSH_MPLS', 512 ofp.OFPAT_POP_MPLS: 'POP_MPLS', 513 ofp.OFPAT_SET_QUEUE: 'SET_QUEUE', 514 ofp.OFPAT_GROUP: 'GROUP', 515 ofp.OFPAT_SET_NW_TTL: 'SET_NW_TTL', 516 ofp.OFPAT_DEC_NW_TTL: 'DEC_NW_TTL', 517 ofp.OFPAT_SET_FIELD: 'SET_FIELD'} 518 519 inst_convert = {ofp.OFPIT_GOTO_TABLE: 'GOTO_TABLE', 520 ofp.OFPIT_WRITE_METADATA: 'WRITE_METADATA', 521 ofp.OFPIT_WRITE_ACTIONS: 'WRITE_ACTIONS', 522 ofp.OFPIT_APPLY_ACTIONS: 'APPLY_ACTIONS', 523 ofp.OFPIT_CLEAR_ACTIONS: 'CLEAR_ACTIONS', 524 ofp.OFPIT_EXPERIMENTER: 'EXPERIMENTER'} 525 526 table_conf_convert = { 527 ofp.OFPTC_TABLE_MISS_CONTROLLER: 'TABLE_MISS_CONTROLLER', 528 ofp.OFPTC_TABLE_MISS_CONTINUE: 'TABLE_MISS_CONTINUE', 529 ofp.OFPTC_TABLE_MISS_DROP: 'TABLE_MISS_DROP', 530 ofp.OFPTC_TABLE_MISS_MASK: 'TABLE_MISS_MASK'} 531 532 tables = [] 533 for msg in msgs: 534 stats = msg.body 535 for stat in stats: 536 match = [] 537 wildcards = [] 538 write_setfields = [] 539 apply_setfields = [] 540 for k, v in oxm_type_convert.items(): 541 if (1 << k) & stat.match: 542 match.append(v) 543 if (1 << k) & stat.wildcards: 544 wildcards.append(v) 545 if (1 << k) & stat.write_setfields: 546 write_setfields.append(v) 547 if (1 << k) & stat.apply_setfields: 548 apply_setfields.append(v) 549 write_actions = [] 550 apply_actions = [] 551 for k, v in act_convert.items(): 552 if (1 << k) & stat.write_actions: 553 write_actions.append(v) 554 if (1 << k) & stat.apply_actions: 555 apply_actions.append(v) 556 instructions = [] 557 for k, v in inst_convert.items(): 558 if (1 << k) & stat.instructions: 559 instructions.append(v) 560 config = [] 561 for k, v in table_conf_convert.items(): 562 if (1 << k) & stat.config: 563 config.append(v) 564 s = {'table_id': UTIL.ofp_table_to_user(stat.table_id), 565 'name': stat.name.decode('utf-8'), 566 'match': match, 567 'wildcards': wildcards, 568 'write_actions': write_actions, 569 'apply_actions': apply_actions, 570 'write_setfields': write_setfields, 571 'apply_setfields': apply_setfields, 572 'metadata_match': stat.metadata_match, 573 'metadata_write': stat.metadata_write, 574 'instructions': instructions, 575 'config': config, 576 'max_entries': stat.max_entries, 577 'active_count': stat.active_count, 578 'lookup_count': stat.lookup_count, 579 'matched_count': stat.matched_count} 580 tables.append(s) 581 582 return {str(dp.id): tables} 583 584 585def get_port_stats(dp, waiters, port=None): 586 if port is None: 587 port = dp.ofproto.OFPP_ANY 588 else: 589 port = str_to_int(port) 590 591 stats = dp.ofproto_parser.OFPPortStatsRequest( 592 dp, port, 0) 593 msgs = [] 594 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 595 596 ports = [] 597 for msg in msgs: 598 for stats in msg.body: 599 s = {'port_no': UTIL.ofp_port_to_user(stats.port_no), 600 'rx_packets': stats.rx_packets, 601 'tx_packets': stats.tx_packets, 602 'rx_bytes': stats.rx_bytes, 603 'tx_bytes': stats.tx_bytes, 604 'rx_dropped': stats.rx_dropped, 605 'tx_dropped': stats.tx_dropped, 606 'rx_errors': stats.rx_errors, 607 'tx_errors': stats.tx_errors, 608 'rx_frame_err': stats.rx_frame_err, 609 'rx_over_err': stats.rx_over_err, 610 'rx_crc_err': stats.rx_crc_err, 611 'collisions': stats.collisions} 612 ports.append(s) 613 614 return {str(dp.id): ports} 615 616 617def get_group_stats(dp, waiters, group_id=None): 618 if group_id is None: 619 group_id = dp.ofproto.OFPG_ALL 620 else: 621 group_id = str_to_int(group_id) 622 623 stats = dp.ofproto_parser.OFPGroupStatsRequest( 624 dp, group_id, 0) 625 msgs = [] 626 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 627 628 groups = [] 629 for msg in msgs: 630 for stats in msg.body: 631 bucket_counters = [] 632 for bucket_counter in stats.bucket_counters: 633 c = {'packet_count': bucket_counter.packet_count, 634 'byte_count': bucket_counter.byte_count} 635 bucket_counters.append(c) 636 g = {'length': stats.length, 637 'group_id': UTIL.ofp_group_to_user(stats.group_id), 638 'ref_count': stats.ref_count, 639 'packet_count': stats.packet_count, 640 'byte_count': stats.byte_count, 641 'bucket_stats': bucket_counters} 642 groups.append(g) 643 644 return {str(dp.id): groups} 645 646 647def get_group_features(dp, waiters): 648 649 ofp = dp.ofproto 650 type_convert = {ofp.OFPGT_ALL: 'ALL', 651 ofp.OFPGT_SELECT: 'SELECT', 652 ofp.OFPGT_INDIRECT: 'INDIRECT', 653 ofp.OFPGT_FF: 'FF'} 654 cap_convert = {ofp.OFPGFC_SELECT_WEIGHT: 'SELECT_WEIGHT', 655 ofp.OFPGFC_SELECT_LIVENESS: 'SELECT_LIVENESS', 656 ofp.OFPGFC_CHAINING: 'CHAINING', 657 ofp.OFPGFC_CHAINING_CHECKS: 'CHAINING_CHECKS'} 658 act_convert = {ofp.OFPAT_OUTPUT: 'OUTPUT', 659 ofp.OFPAT_COPY_TTL_OUT: 'COPY_TTL_OUT', 660 ofp.OFPAT_COPY_TTL_IN: 'COPY_TTL_IN', 661 ofp.OFPAT_SET_MPLS_TTL: 'SET_MPLS_TTL', 662 ofp.OFPAT_DEC_MPLS_TTL: 'DEC_MPLS_TTL', 663 ofp.OFPAT_PUSH_VLAN: 'PUSH_VLAN', 664 ofp.OFPAT_POP_VLAN: 'POP_VLAN', 665 ofp.OFPAT_PUSH_MPLS: 'PUSH_MPLS', 666 ofp.OFPAT_POP_MPLS: 'POP_MPLS', 667 ofp.OFPAT_SET_QUEUE: 'SET_QUEUE', 668 ofp.OFPAT_GROUP: 'GROUP', 669 ofp.OFPAT_SET_NW_TTL: 'SET_NW_TTL', 670 ofp.OFPAT_DEC_NW_TTL: 'DEC_NW_TTL', 671 ofp.OFPAT_SET_FIELD: 'SET_FIELD'} 672 673 stats = dp.ofproto_parser.OFPGroupFeaturesStatsRequest(dp, 0) 674 msgs = [] 675 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 676 677 features = [] 678 for msg in msgs: 679 feature = msg.body 680 types = [] 681 for k, v in type_convert.items(): 682 if (1 << k) & feature.types: 683 types.append(v) 684 capabilities = [] 685 for k, v in cap_convert.items(): 686 if k & feature.capabilities: 687 capabilities.append(v) 688 max_groups = [] 689 for k, v in type_convert.items(): 690 max_groups.append({v: feature.max_groups[k]}) 691 actions = [] 692 for k1, v1 in type_convert.items(): 693 acts = [] 694 for k2, v2 in act_convert.items(): 695 if (1 << k2) & feature.actions[k1]: 696 acts.append(v2) 697 actions.append({v1: acts}) 698 f = {'types': types, 699 'capabilities': capabilities, 700 'max_groups': max_groups, 701 'actions': actions} 702 features.append(f) 703 704 return {str(dp.id): features} 705 706 707def get_group_desc(dp, waiters): 708 709 type_convert = {dp.ofproto.OFPGT_ALL: 'ALL', 710 dp.ofproto.OFPGT_SELECT: 'SELECT', 711 dp.ofproto.OFPGT_INDIRECT: 'INDIRECT', 712 dp.ofproto.OFPGT_FF: 'FF'} 713 714 stats = dp.ofproto_parser.OFPGroupDescStatsRequest(dp, 0) 715 msgs = [] 716 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 717 718 descs = [] 719 for msg in msgs: 720 for stats in msg.body: 721 buckets = [] 722 for bucket in stats.buckets: 723 actions = [] 724 for action in bucket.actions: 725 actions.append(action_to_str(action)) 726 b = {'weight': bucket.weight, 727 'watch_port': bucket.watch_port, 728 'watch_group': bucket.watch_group, 729 'actions': actions} 730 buckets.append(b) 731 d = {'type': type_convert.get(stats.type), 732 'group_id': UTIL.ofp_group_to_user(stats.group_id), 733 'buckets': buckets} 734 descs.append(d) 735 736 return {str(dp.id): descs} 737 738 739def get_port_desc(dp, waiters): 740 741 stats = dp.ofproto_parser.OFPFeaturesRequest(dp) 742 msgs = [] 743 ofctl_utils.send_stats_request(dp, stats, waiters, msgs, LOG) 744 745 descs = [] 746 747 for msg in msgs: 748 stats = msg.ports 749 for stat in stats.values(): 750 d = {'port_no': UTIL.ofp_port_to_user(stat.port_no), 751 'hw_addr': stat.hw_addr, 752 'name': stat.name.decode('utf-8'), 753 'config': stat.config, 754 'state': stat.state, 755 'curr': stat.curr, 756 'advertised': stat.advertised, 757 'supported': stat.supported, 758 'peer': stat.peer, 759 'curr_speed': stat.curr_speed, 760 'max_speed': stat.max_speed} 761 descs.append(d) 762 763 return {str(dp.id): descs} 764 765 766def get_role(dp, waiters, to_user=True): 767 return ofctl_utils.get_role(dp, waiters, to_user) 768 769 770def mod_flow_entry(dp, flow, cmd): 771 cookie = str_to_int(flow.get('cookie', 0)) 772 cookie_mask = str_to_int(flow.get('cookie_mask', 0)) 773 table_id = UTIL.ofp_table_from_user(flow.get('table_id', 0)) 774 idle_timeout = str_to_int(flow.get('idle_timeout', 0)) 775 hard_timeout = str_to_int(flow.get('hard_timeout', 0)) 776 priority = str_to_int(flow.get('priority', 0)) 777 buffer_id = UTIL.ofp_buffer_from_user( 778 flow.get('buffer_id', dp.ofproto.OFP_NO_BUFFER)) 779 out_port = UTIL.ofp_port_from_user( 780 flow.get('out_port', dp.ofproto.OFPP_ANY)) 781 out_group = UTIL.ofp_group_from_user( 782 flow.get('out_group', dp.ofproto.OFPG_ANY)) 783 flags = str_to_int(flow.get('flags', 0)) 784 match = to_match(dp, flow.get('match', {})) 785 inst = to_actions(dp, flow.get('actions', [])) 786 787 flow_mod = dp.ofproto_parser.OFPFlowMod( 788 dp, cookie, cookie_mask, table_id, cmd, idle_timeout, 789 hard_timeout, priority, buffer_id, out_port, out_group, 790 flags, match, inst) 791 792 ofctl_utils.send_msg(dp, flow_mod, LOG) 793 794 795def mod_group_entry(dp, group, cmd): 796 797 type_convert = {'ALL': dp.ofproto.OFPGT_ALL, 798 'SELECT': dp.ofproto.OFPGT_SELECT, 799 'INDIRECT': dp.ofproto.OFPGT_INDIRECT, 800 'FF': dp.ofproto.OFPGT_FF} 801 802 type_ = type_convert.get(group.get('type', 'ALL')) 803 if type_ is None: 804 LOG.error('Unknown group type: %s', group.get('type')) 805 806 group_id = UTIL.ofp_group_from_user(group.get('group_id', 0)) 807 808 buckets = [] 809 for bucket in group.get('buckets', []): 810 weight = str_to_int(bucket.get('weight', 0)) 811 watch_port = str_to_int( 812 bucket.get('watch_port', dp.ofproto.OFPP_ANY)) 813 watch_group = str_to_int( 814 bucket.get('watch_group', dp.ofproto.OFPG_ANY)) 815 actions = [] 816 for dic in bucket.get('actions', []): 817 action = to_action(dp, dic) 818 if action is not None: 819 actions.append(action) 820 buckets.append(dp.ofproto_parser.OFPBucket( 821 weight, watch_port, watch_group, actions)) 822 823 group_mod = dp.ofproto_parser.OFPGroupMod( 824 dp, cmd, type_, group_id, buckets) 825 826 ofctl_utils.send_msg(dp, group_mod, LOG) 827 828 829def mod_port_behavior(dp, port_config): 830 port_no = UTIL.ofp_port_from_user(port_config.get('port_no', 0)) 831 hw_addr = str(port_config.get('hw_addr')) 832 config = str_to_int(port_config.get('config', 0)) 833 mask = str_to_int(port_config.get('mask', 0)) 834 advertise = str_to_int(port_config.get('advertise')) 835 836 port_mod = dp.ofproto_parser.OFPPortMod( 837 dp, port_no, hw_addr, config, mask, advertise) 838 839 ofctl_utils.send_msg(dp, port_mod, LOG) 840 841 842def set_role(dp, role): 843 r = UTIL.ofp_role_from_user(role.get('role', dp.ofproto.OFPCR_ROLE_EQUAL)) 844 role_request = dp.ofproto_parser.OFPRoleRequest(dp, r, 0) 845 ofctl_utils.send_msg(dp, role_request, LOG) 846 847 848# NOTE(jkoelker) Alias common funcitons 849send_experimenter = ofctl_utils.send_experimenter 850