diff options
author | OHMURA Kei <ohmura.kei@lab.ntt.co.jp> | 2013-07-23 21:04:04 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2013-07-24 08:36:08 +0900 |
commit | afefe3c3cd8fe1130c3cb617ff811b557538cb62 (patch) | |
tree | 2eaa718bdf3c89caf6eac7344fa3469f3ffdc976 | |
parent | db40bc0f98abc84dcdbd3fa4d19aa573d94188d9 (diff) |
add ofctl_v1_3 library
Signed-off-by: OHMURA Kei <ohmura.kei@lab.ntt.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/ofctl_v1_3.py | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py new file mode 100644 index 00000000..bd11112d --- /dev/null +++ b/ryu/lib/ofctl_v1_3.py @@ -0,0 +1,264 @@ +# 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 struct +import socket +import logging + +from ryu.ofproto import inet +from ryu.ofproto import ofproto_v1_3 +from ryu.ofproto import ofproto_v1_3_parser +from ryu.lib import hub +from ryu.lib import mac + + +LOG = logging.getLogger('ryu.lib.ofctl_v1_3') + +DEFAULT_TIMEOUT = 1.0 + + +def to_actions(dp, acts): + inst = [] + actions = [] + ofp = dp.ofproto + parser = dp.ofproto_parser + + for a in acts: + action_type = a.get('type') + if action_type == 'OUTPUT': + out_port = int(a.get('port', ofproto_v1_3.OFPP_ANY)) + max_len = int(a.get('max_len', 0)) + actions.append((parser.OFPActionOutput(out_port, + max_len))) + elif action_type == 'COPY_TTL_OUT': + pass + elif action_type == 'COPY_TTL_IN': + pass + elif action_type == 'SET_MPLS_TTL': + mpls_ttl = int(a.get('mpls_ttl')) + actions.append((parser.OFPActionSetMplsTtl(mpls_ttl))) + elif action_type == 'DEC_MPLS_TTL': + actions.append((parser.OFPActionDecMplsTtl())) + elif action_type == 'PUSH_VLAN': + ethertype = int(a.get('ethertype')) + actions.append((parser.OFPActionPushVlan(ethertype))) + elif action_type == 'POP_VLAN': + actions.append(parser.OFPActionPopVlan()) + elif action_type == 'PUSH_MPLS': + ethertype = int(a.get('ethertype')) + actions.append(parser.OFPActionPushMpls(ethertype)) + elif action_type == 'POP_MPLS': + actions.append(parser.OFPActionPopMpls()) + elif action_type == 'SET_QUEUE': + queue_id = int(a.get('queue_id')) + actions.append(parser.OFPActionSetQueue(queue_id)) + elif action_type == 'GROUP': + pass + elif action_type == 'SET_NW_TTL': + nw_ttl = int(a.get('nw_ttl')) + actions.append(parser.OFPActionSetNwTtl(nw_ttl)) + elif action_type == 'DEC_NW_TTL': + actions.append(parser.OFPActionDecNwTtl()) + elif action_type == 'SET_FIELD': + field = a.get('field') + value = a.get('value') + if field == 'eth_dst': + field = ofp.OXM_OF_ETH_DST + value = mac.haddr_to_bin(str(value)) + elif field == 'eth_src': + field = ofp.OXM_OF_ETH_SRC + value = mac.haddr_to_bin(str(value)) + elif field == 'vlan_vid': + field = ofp.OXM_OF_VLAN_VID + value = int(value) + elif field == 'mpls_label': + field = ofp.OXM_OF_MPLS_LABEL + value = int(value) + else: + LOG.debug('Unknown field: %s' % field) + continue + f = parser.OFPMatchField.make(field, value) + actions.append(parser.OFPActionSetField(f)) + elif action_type == 'PUSH_PBB': + pass + elif action_type == 'POP_PBB': + pass + elif action_type == 'GOTO_TABLE': + table_id = int(a.get('table_id')) + inst.append(parser.OFPInstructionGotoTable(table_id)) + else: + LOG.debug('Unknown action type: %s' % action_type) + + inst.append(parser.OFPInstructionActions(ofp.OFPIT_APPLY_ACTIONS, + actions)) + return inst + + +def to_match(dp, attrs): + match = dp.ofproto_parser.OFPMatch() + + convert = {'in_port': int, + 'dl_src': mac.haddr_to_bin, + 'dl_dst': mac.haddr_to_bin, + 'dl_type': int, + 'dl_vlan': int, + 'nw_src': to_match_ip, + 'nw_dst': to_match_ip, + 'nw_proto': int, + 'tp_src': int, + 'tp_dst': int, + 'mpls_label': int} + + match_append = {'in_port': match.set_in_port, + 'dl_src': match.set_dl_src, + 'dl_dst': match.set_dl_dst, + 'dl_type': match.set_dl_type, + 'dl_vlan': match.set_vlan_vid, + 'nw_src': match.set_ipv4_src_masked, + 'nw_dst': match.set_ipv4_dst_masked, + 'nw_proto': match.set_ip_proto, + 'tp_src': to_match_tpsrc, + 'tp_dst': to_match_tpdst, + 'mpls_label': match.set_mpls_label} + + for key, value in attrs.items(): + if key in convert: + value = convert[key](value) + if key in match_append: + if key == 'nw_src' or key == 'nw_dst': + # IP address + ip = value[0] + mask = value[1] + match_append[key](ip, mask) + elif key == 'tp_src' or key == 'tp_dst': + # tp_src/dst + match = match_append[key](value, match, attrs) + else: + # others + match_append[key](value) + + return match + + +def to_match_tpsrc(value, match, rest): + match_append = {inet.IPPROTO_TCP: match.set_tcp_src, + inet.IPPROTO_UDP: match.set_udp_src} + + nw_proto = rest.get('nw_proto', 0) + if nw_proto in match_append: + match_append[nw_proto](value) + + return match + + +def to_match_tpdst(value, match, rest): + match_append = {inet.IPPROTO_TCP: match.set_tcp_dst, + inet.IPPROTO_UDP: match.set_udp_dst} + + nw_proto = rest.get('nw_proto', 0) + if nw_proto in match_append: + match_append[nw_proto](value) + + return match + + +def to_match_ip(value): + ip_mask = value.split('/') + # ip + ipv4 = struct.unpack('!I', socket.inet_aton(ip_mask[0]))[0] + # netmask + mask = 32 + if len(ip_mask) == 2: + mask = int(ip_mask[1]) + netmask = ofproto_v1_3_parser.UINT32_MAX << 32 - mask\ + & ofproto_v1_3_parser.UINT32_MAX + + return ipv4, netmask + + +def send_stats_request(dp, stats, waiters, msgs): + dp.set_xid(stats) + waiters_per_dp = waiters.setdefault(dp.id, {}) + lock = hub.Event() + waiters_per_dp[stats.xid] = (lock, msgs) + dp.send_msg(stats) + + try: + lock.wait(timeout=DEFAULT_TIMEOUT) + except hub.Timeout: + del waiters_per_dp[stats.xid] + + +def get_flow_stats(dp, waiters): + table_id = 0 + flags = 0 + out_port = dp.ofproto.OFPP_ANY + out_group = dp.ofproto.OFPG_ANY + cookie = 0 + cookie_mask = 0 + match = dp.ofproto_parser.OFPMatch() + + stats = dp.ofproto_parser.OFPFlowStatsRequest( + dp, flags, table_id, out_port, out_group, cookie, cookie_mask, + match) + + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + flows = [] + for msg in msgs: + for stats in msg.body: + actions = [] + for action in stats.instructions: + actions.append(action.to_jsondict()) + match = stats.match.to_jsondict() + + 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, + 'table_id': stats.table_id, + 'match': match, + 'actions': actions} + flows.append(s) + flows = {str(dp.id): flows} + + return flows + + +def mod_flow_entry(dp, flow, cmd): + cookie = int(flow.get('cookie', 0)) + cookie_mask = int(flow.get('cookie_mask', 0)) + table_id = int(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 = int(flow.get('buffer_id', dp.ofproto.OFP_NO_BUFFER)) + out_port = int(flow.get('out_port', dp.ofproto.OFPP_ANY)) + out_group = int(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) + + dp.send_msg(flow_mod) |