diff options
author | OHMURA Kei <ohmura.kei@lab.ntt.co.jp> | 2012-09-03 18:46:40 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2012-10-30 11:39:52 +0900 |
commit | 3e74c789e992b4076dee8db2ad850a5429443cee (patch) | |
tree | 4bcafaaf752af451219f3fd2e9347edea4864cc2 | |
parent | 51b3b9a2bd086d0bb8e21a0e0e3db015c7e55f7f (diff) |
ryu/lib/ofctl_v1_0: introduce OF interface
This patch provides the raw OF interface. We can talk with a switch
by using the OF interface via some protocols such as REST.
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_0.py | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/ryu/lib/ofctl_v1_0.py b/ryu/lib/ofctl_v1_0.py new file mode 100644 index 00000000..2ec36c09 --- /dev/null +++ b/ryu/lib/ofctl_v1_0.py @@ -0,0 +1,237 @@ +# Copyright (C) 2012 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 logging + +import gevent + +from ryu.ofproto import ofproto_v1_0 +from ryu.lib.mac import haddr_to_bin, haddr_to_str + + +LOG = logging.getLogger('ryu.lib.ofctl_v1_0') + +DEFAULT_TIMEOUT = 1.0 # TODO:XXX + + +def to_actions(dp, acts): + actions = [] + for a in acts: + action_type = a.get('type') + if action_type == 'OUTPUT': + out_port = int(a.get('port', ofproto_v1_0.OFPP_NONE)) + actions.append(dp.ofproto_parser.OFPActionOutput(out_port)) + elif action_type == 'SET_VLAN_VID': + vlan_vid = int(a.get('vlan_vid', 0xffff)) + actions.append(dp.ofproto_parser.OFPActionVlanVid(vlan_vid)) + elif action_type == 'SET_VLAN_PCP': + vlan_pcp = int(a.get('vlan_pcp', 0)) + actions.append(dp.ofproto_parser.OFPActionVlanPcp(vlan_pcp)) + elif action_type == 'STRIP_VLAN': + actions.append(dp.ofproto_parser.OFPActionStripVlan()) + elif action_type == 'SET_DL_SRC': + dl_src = haddr_to_bin(a.get('dl_src')) + actions.append(dp.ofproto_parser.OFPActionSetDlSrc(dl_src)) + elif action_type == 'SET_DL_DST': + dl_dst = haddr_to_bin(a.get('dl_dst')) + actions.append(dp.ofproto_parser.OFPActionSetDlDst(dl_dst)) + else: + LOG.debug('Unknown action type') + + return actions + + +def to_match(dp, attrs): + ofp = dp.ofproto + + wildcards = ofp.OFPFW_ALL + in_port = 0 + dl_src = 0 + dl_dst = 0 + dl_vlan = 0 + dl_vlan_pcp = 0 + dl_type = 0 + nw_tos = 0 + nw_proto = 0 + nw_src = 0 + nw_dst = 0 + tp_src = 0 + tp_dst = 0 + + for key, value in attrs.items(): + if key == 'in_port': + in_port = int(value) + wildcards &= ~ofp.OFPFW_IN_PORT + elif key == 'dl_src': + dl_src = haddr_to_bin(value) + wildcards &= ~ofp.OFPFW_DL_DST + elif key == 'dl_dst': + dl_dst = haddr_to_bin(value) + wildcards &= ~ofp.OFPFW_DL_DST + elif key == 'dl_vlan': + dl_vlan = int(value) + wildcards &= ~ofp.OFPFW_DL_VLAN + elif key == 'dl_vlan_pcp': + dl_vlan_pcp = int(value) + wildcards &= ~ofp.OFPFW_DL_VLAN_PCP + elif key == 'dl_type': + dl_type = int(value) + wildcards &= ~ofp.OFPFW_DL_TYPE + elif key == 'nw_tos': + nw_tos = int(value) + wildcards &= ~ofp.OFPFW_NW_TOS + elif key == 'nw_proto': + nw_proto = int(value) + wildcards &= ~ofp.OFPFW_NW_PROTO + elif key == 'nw_src': + pass + elif key == 'nw_dst': + pass + elif key == 'tp_src': + tp_src = int(value) + wildcards &= ~ofp.OFPFW_TP_SRC + elif key == 'tp_dst': + tp_dst = int(value) + wildcards &= ~ofp.OFPFW_TP_DST + else: + print "unknown match name ", key, value, len(key) + + match = dp.ofproto_parser.OFPMatch( + wildcards, in_port, dl_src, dl_dst, dl_vlan, dl_vlan_pcp, + dl_type, nw_tos, nw_proto, nw_src, nw_dst, tp_src, tp_dst) + + return match + + +def send_stats_request(dp, stats, waiters, msgs): + dp.set_xid(stats) + waiters = waiters.setdefault(dp.id, {}) + lock = gevent.event.AsyncResult() + waiters[stats.xid] = (lock, msgs) + dp.send_msg(stats) + + try: + lock.get(timeout=DEFAULT_TIMEOUT) + except gevent.Timeout: + del waiters[dp.id][stats.xid] + + +def get_desc_stats(dp, waiters): + stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0) + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + for msg in msgs: + stats = msg.body + s = {'mfr_desc': stats.mfr_desc, + 'hw_desc': stats.hw_desc, + 'sw_desc': stats.sw_desc, + 'serial_num': stats.serial_num, + 'dp_desc': stats.dp_desc} + desc = {str(dp.id): s} + return desc + + +def get_flow_stats(dp, waiters): + match = dp.ofproto_parser.OFPMatch( + dp.ofproto.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + stats = dp.ofproto_parser.OFPFlowStatsRequest( + dp, 0, match, 0xff, dp.ofproto.OFPP_NONE) + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + flows = [] + for msg in msgs: + for stats in msg.body: + s = {'priority': stats.priority, + 'cookie': stats.cookie, + 'idle_timeout': stats.idle_timeout, + 'hard_timeout': stats.hard_timeout, + 'match': {'dl_dst': haddr_to_str(stats.match.dl_dst), + 'dl_src': haddr_to_str(stats.match.dl_src), + 'dl_type': stats.match.dl_type, + 'dl_vlan': stats.match.dl_vlan, + 'dl_vlan_pcp': stats.match.dl_vlan_pcp, + 'in_port': stats.match.in_port, + 'nw_dst': stats.match.nw_dst, + 'nw_proto': stats.match.nw_proto, + 'nw_src': stats.match.nw_src, + 'tp_src': stats.match.tp_src, + 'tp_dst': stats.match.tp_dst}, + '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} + flows.append(s) + flows = {str(dp.id): flows} + return flows + + +def get_port_stats(dp, waiters): + stats = dp.ofproto_parser.OFPPortStatsRequest( + dp, 0, dp.ofproto.OFPP_NONE) + msgs = [] + send_stats_request(dp, stats, waiters, msgs) + + ports = [] + for msg in msgs: + for stats in msg.body: + s = {'port_no': stats.port_no, + 'rx_packets': stats.rx_packets, + 'tx_packets': stats.tx_packets, + 'rx_bytes': stats.rx_bytes, + 'tx_bytes': stats.tx_bytes, + 'rx_dropped': stats.rx_dropped, + 'tx_dropped': stats.tx_dropped, + 'rx_errors': stats.rx_errors, + 'tx_errors': stats.tx_errors, + 'rx_frame_err': stats.rx_frame_err, + 'rx_over_err': stats.rx_over_err, + 'rx_crc_err': stats.rx_crc_err, + 'collisions': stats.collisions} + ports.append(s) + ports = {str(dp.id): ports} + return ports + + +def push_flow_entry(dp, flow): + cookie = int(flow.get('cookie', 0)) + priority = int(flow.get('priority', + dp.ofproto.OFP_DEFAULT_PRIORITY)) + flags = int(flow.get('flags', 0)) + idle_timeout = int(flow.get('idle_timeout', 0)) + hard_timeout = int(flow.get('hard_timeout', 0)) + actions = to_actions(dp, flow.get('actions', {})) + match = to_match(dp, flow.get('match', {})) + + flow_mod = dp.ofproto_parser.OFPFlowMod( + datapath=dp, match=match, cookie=cookie, + command=dp.ofproto.OFPFC_ADD, idle_timeout=idle_timeout, + hard_timeout=hard_timeout, priority=priority, flags=flags, + actions=actions) + + dp.send_msg(flow_mod) + + +def delete_flow_entry(dp): + match = dp.ofproto_parser.OFPMatch( + dp.ofproto.OFPFW_ALL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + + flow_mod = dp.ofproto_parser.OFPFlowMod( + datapath=dp, match=match, cookie=0, + command=dp.ofproto.OFPFC_DELETE) + + dp.send_msg(flow_mod) |