From 369df998227ca39a753423709a767f93dbdfd624 Mon Sep 17 00:00:00 2001 From: Jason Kölker Date: Tue, 29 Mar 2016 19:18:38 +0000 Subject: lib/ofctl_v1_[34]: Consolidate common functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jason Kölker Signed-off-by: FUJITA Tomonori --- ryu/lib/ofctl_utils.py | 153 ++++++++++++++++++++++++++++++++++++++++++++- ryu/lib/ofctl_v1_3.py | 166 ++++++++----------------------------------------- ryu/lib/ofctl_v1_4.py | 161 +++++++---------------------------------------- 3 files changed, 198 insertions(+), 282 deletions(-) diff --git a/ryu/lib/ofctl_utils.py b/ryu/lib/ofctl_utils.py index e3b80e6d..c6578cfe 100644 --- a/ryu/lib/ofctl_utils.py +++ b/ryu/lib/ofctl_utils.py @@ -13,17 +13,162 @@ # See the License for the specific language governing permissions and # limitations under the License. +import base64 import logging +import netaddr +import six + from ryu.lib import hub LOG = logging.getLogger(__name__) DEFAULT_TIMEOUT = 1.0 +# NOTE(jkoelker) Constants for converting actions +OUTPUT = 'OUTPUT' +COPY_TTL_OUT = 'COPY_TTL_OUT' +COPY_TTL_IN = 'COPY_TTL_IN' +SET_MPLS_TTL = 'SET_MPLS_TTL' +DEC_MPLS_TTL = 'DEC_MPLS_TTL' +PUSH_VLAN = 'PUSH_VLAN' +POP_VLAN = 'POP_VLAN' +PUSH_MPLS = 'PUSH_MPLS' +POP_MPLS = 'POP_MPLS' +SET_QUEUE = 'SET_QUEUE' +GROUP = 'GROUP' +SET_NW_TTL = 'SET_NW_TTL' +DEC_NW_TTL = 'DEC_NW_TTL' +SET_FIELD = 'SET_FIELD' +PUSH_PBB = 'PUSH_PBB' +POP_PBB = 'POP_PBB' +EXPERIMENTER = 'EXPERIMENTER' + + +def match_vid_to_str(value, mask, ofpvid_present): + if mask is not None: + return '0x%04x/0x%04x' % (value, mask) + + if value & ofpvid_present: + return str(value & ~ofpvid_present) + + return '0x%04x' % value + + +def to_action(dic, ofp, parser, action_type, util): + actions = {COPY_TTL_OUT: parser.OFPActionCopyTtlOut, + COPY_TTL_IN: parser.OFPActionCopyTtlIn, + DEC_MPLS_TTL: parser.OFPActionDecMplsTtl, + POP_VLAN: parser.OFPActionPopVlan, + DEC_NW_TTL: parser.OFPActionDecNwTtl, + POP_PBB: parser.OFPActionPopPbb} + + need_ethertype = {PUSH_VLAN: parser.OFPActionPushVlan, + PUSH_MPLS: parser.OFPActionPushMpls, + POP_MPLS: parser.OFPActionPopMpls, + PUSH_PBB: parser.OFPActionPushPbb} + + if action_type in actions: + return actions[action_type]() + + elif action_type in need_ethertype: + ethertype = int(dic.get('ethertype')) + return need_ethertype[action_type](ethertype) + + elif action_type == OUTPUT: + out_port = util.ofp_port_from_user(dic.get('port', ofp.OFPP_ANY)) + max_len = util.ofp_cml_from_user(dic.get('max_len', ofp.OFPCML_MAX)) + return parser.OFPActionOutput(out_port, max_len) + + elif action_type == SET_MPLS_TTL: + mpls_ttl = int(dic.get('mpls_ttl')) + return parser.OFPActionSetMplsTtl(mpls_ttl) + + elif action_type == SET_QUEUE: + queue_id = util.ofp_queue_from_user(dic.get('queue_id')) + return parser.OFPActionSetQueue(queue_id) + + elif action_type == GROUP: + group_id = util.ofp_group_from_user(dic.get('group_id')) + return parser.OFPActionGroup(group_id) + + elif action_type == SET_NW_TTL: + nw_ttl = int(dic.get('nw_ttl')) + return parser.OFPActionSetNwTtl(nw_ttl) + + elif action_type == SET_FIELD: + field = dic.get('field') + value = dic.get('value') + return parser.OFPActionSetField(**{field: value}) + + elif action_type == EXPERIMENTER: + experimenter = int(dic.get('experimenter')) + data_type = dic.get('data_type', 'ascii') + + if data_type not in ('ascii', 'base64'): + LOG.error('Unknown data type: %s', data_type) + return None + + data = dic.get('data', '') + if data_type == 'base64': + data = base64.b64decode(data) + return parser.OFPActionExperimenterUnknown(experimenter, data) + + return None -def str_to_int(str_num): - return int(str(str_num), 0) + +def to_match_eth(value): + if '/' in value: + value = value.split('/') + return value[0], value[1] + + return value + + +def to_match_ip(value): + if '/' in value: + (ip_addr, ip_mask) = value.split('/') + + if ip_mask.isdigit(): + ip = netaddr.ip.IPNetwork(value) + ip_addr = str(ip.ip) + ip_mask = str(ip.netmask) + + return ip_addr, ip_mask + + return value + + +def to_match_vid(value, ofpvid_present): + # NOTE: If "vlan_id" field is described as decimal int value + # (and decimal string value), it is treated as values of + # VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically + # applied. OTOH, If it is described as hexadecimal string, + # treated as values of oxm_value (including OFPVID_PRESENT + # bit), and OFPVID_PRESENT bit is NOT automatically applied + if isinstance(value, six.integer_types): + # described as decimal int value + return value | ofpvid_present + + else: + if '/' in value: + val = value.split('/') + return int(val[0], 0), int(val[1], 0) + + else: + if value.isdigit(): + # described as decimal string value + return int(value, 10) | ofpvid_present + + return int(value, 0) + + +def to_match_masked_int(value): + if isinstance(value, str) and '/' in value: + value = value.split('/') + return (str_to_int(value[0]), str_to_int(value[1])) + + return str_to_int(value) def send_msg(dp, msg, logger=None): @@ -61,6 +206,10 @@ def send_stats_request(dp, stats, waiters, msgs, logger=None): del waiters_per_dp[stats.xid] +def str_to_int(str_num): + return int(str(str_num), 0) + + class OFCtlUtil(object): def __init__(self, ofproto): diff --git a/ryu/lib/ofctl_v1_3.py b/ryu/lib/ofctl_v1_3.py index 987e8f60..c4d62c36 100644 --- a/ryu/lib/ofctl_v1_3.py +++ b/ryu/lib/ofctl_v1_3.py @@ -15,7 +15,6 @@ import base64 import logging -import netaddr from ryu.ofproto import ether from ryu.ofproto import inet @@ -36,66 +35,8 @@ UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_3) def to_action(dp, dic): ofp = dp.ofproto parser = dp.ofproto_parser - action_type = dic.get('type') - if action_type == 'OUTPUT': - out_port = UTIL.ofp_port_from_user(dic.get('port', ofp.OFPP_ANY)) - max_len = UTIL.ofp_cml_from_user(dic.get('max_len', ofp.OFPCML_MAX)) - result = parser.OFPActionOutput(out_port, max_len) - elif action_type == 'COPY_TTL_OUT': - result = parser.OFPActionCopyTtlOut() - elif action_type == 'COPY_TTL_IN': - result = parser.OFPActionCopyTtlIn() - elif action_type == 'SET_MPLS_TTL': - mpls_ttl = int(dic.get('mpls_ttl')) - result = parser.OFPActionSetMplsTtl(mpls_ttl) - elif action_type == 'DEC_MPLS_TTL': - result = parser.OFPActionDecMplsTtl() - elif action_type == 'PUSH_VLAN': - ethertype = int(dic.get('ethertype')) - result = parser.OFPActionPushVlan(ethertype) - elif action_type == 'POP_VLAN': - result = parser.OFPActionPopVlan() - elif action_type == 'PUSH_MPLS': - ethertype = int(dic.get('ethertype')) - result = parser.OFPActionPushMpls(ethertype) - elif action_type == 'POP_MPLS': - ethertype = int(dic.get('ethertype')) - result = parser.OFPActionPopMpls(ethertype) - elif action_type == 'SET_QUEUE': - queue_id = UTIL.ofp_queue_from_user(dic.get('queue_id')) - result = parser.OFPActionSetQueue(queue_id) - elif action_type == 'GROUP': - group_id = UTIL.ofp_group_from_user(dic.get('group_id')) - result = parser.OFPActionGroup(group_id) - elif action_type == 'SET_NW_TTL': - nw_ttl = int(dic.get('nw_ttl')) - result = parser.OFPActionSetNwTtl(nw_ttl) - elif action_type == 'DEC_NW_TTL': - result = parser.OFPActionDecNwTtl() - elif action_type == 'SET_FIELD': - field = dic.get('field') - value = dic.get('value') - result = parser.OFPActionSetField(**{field: value}) - elif action_type == 'PUSH_PBB': - ethertype = int(dic.get('ethertype')) - result = parser.OFPActionPushPbb(ethertype) - elif action_type == 'POP_PBB': - result = parser.OFPActionPopPbb() - elif action_type == 'EXPERIMENTER': - experimenter = int(dic.get('experimenter')) - data_type = dic.get('data_type', 'ascii') - if data_type not in ['ascii', 'base64']: - LOG.error('Unknown data type: %s', data_type) - return None - data = dic.get('data', '') - if data_type == 'base64': - data = base64.b64decode(data) - result = parser.OFPActionExperimenterUnknown(experimenter, data) - else: - result = None - - return result + return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL) def to_actions(dp, acts): @@ -252,11 +193,11 @@ def actions_to_str(instructions): def to_match(dp, attrs): convert = {'in_port': UTIL.ofp_port_from_user, 'in_phy_port': int, - 'metadata': to_match_masked_int, - 'dl_dst': to_match_eth, - 'dl_src': to_match_eth, - 'eth_dst': to_match_eth, - 'eth_src': to_match_eth, + 'metadata': ofctl_utils.to_match_masked_int, + 'dl_dst': ofctl_utils.to_match_eth, + 'dl_src': ofctl_utils.to_match_eth, + 'eth_dst': ofctl_utils.to_match_eth, + 'eth_src': ofctl_utils.to_match_eth, 'dl_type': int, 'eth_type': int, 'dl_vlan': to_match_vid, @@ -266,10 +207,10 @@ def to_match(dp, attrs): 'ip_ecn': int, 'nw_proto': int, 'ip_proto': int, - 'nw_src': to_match_ip, - 'nw_dst': to_match_ip, - 'ipv4_src': to_match_ip, - 'ipv4_dst': to_match_ip, + 'nw_src': ofctl_utils.to_match_ip, + 'nw_dst': ofctl_utils.to_match_ip, + 'ipv4_src': ofctl_utils.to_match_ip, + 'ipv4_dst': ofctl_utils.to_match_ip, 'tp_src': int, 'tp_dst': int, 'tcp_src': int, @@ -281,24 +222,24 @@ def to_match(dp, attrs): 'icmpv4_type': int, 'icmpv4_code': int, 'arp_op': int, - 'arp_spa': to_match_ip, - 'arp_tpa': to_match_ip, - 'arp_sha': to_match_eth, - 'arp_tha': to_match_eth, - 'ipv6_src': to_match_ip, - 'ipv6_dst': to_match_ip, + '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': int, 'icmpv6_type': int, 'icmpv6_code': int, - 'ipv6_nd_target': to_match_ip, - 'ipv6_nd_sll': to_match_eth, - 'ipv6_nd_tll': to_match_eth, + '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': int, 'mpls_tc': int, 'mpls_bos': int, - 'pbb_isid': to_match_masked_int, - 'tunnel_id': to_match_masked_int, - 'ipv6_exthdr': to_match_masked_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} keys = {'dl_dst': 'eth_dst', 'dl_src': 'eth_src', @@ -342,55 +283,8 @@ def to_match(dp, attrs): return dp.ofproto_parser.OFPMatch(**kwargs) -def to_match_eth(value): - if '/' in value: - value = value.split('/') - return value[0], value[1] - else: - return value - - -def to_match_ip(value): - if '/' in value: - (ip_addr, ip_mask) = value.split('/') - if ip_mask.isdigit(): - ip = netaddr.ip.IPNetwork(value) - ip_addr = str(ip.ip) - ip_mask = str(ip.netmask) - return ip_addr, ip_mask - else: - return value - - def to_match_vid(value): - # NOTE: If "vlan_id/dl_vlan" field is described as decimal int value - # (and decimal string value), it is treated as values of - # VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically - # applied. OTOH, If it is described as hexadecimal string, - # treated as values of oxm_value (including OFPVID_PRESENT - # bit), and OFPVID_PRESENT bit is NOT automatically applied. - if isinstance(value, int): - # described as decimal int value - return value | ofproto_v1_3.OFPVID_PRESENT - else: - if '/' in value: - val = value.split('/') - return int(val[0], 0), int(val[1], 0) - else: - if value.isdigit(): - # described as decimal string value - return int(value, 10) | ofproto_v1_3.OFPVID_PRESENT - else: - return int(value, 0) - - -def to_match_masked_int(value): - if isinstance(value, str) and '/' in value: - value = value.split('/') - return (ofctl_utils.str_to_int(value[0]), - ofctl_utils.str_to_int(value[1])) - else: - return ofctl_utils.str_to_int(value) + return ofctl_utils.to_match_vid(value, ofproto_v1_3.OFPVID_PRESENT) def match_to_str(ofmatch): @@ -420,7 +314,8 @@ def match_to_str(ofmatch): mask = match_field['OXMTlv']['mask'] value = match_field['OXMTlv']['value'] if key == 'dl_vlan': - value = match_vid_to_str(value, mask) + value = ofctl_utils.match_vid_to_str(value, mask, + ofproto_v1_3.OFPVID_PRESENT) elif key == 'in_port': value = UTIL.ofp_port_to_user(value) else: @@ -431,17 +326,6 @@ def match_to_str(ofmatch): return match -def match_vid_to_str(value, mask): - if mask is not None: - value = '0x%04x/0x%04x' % (value, mask) - else: - if value & ofproto_v1_3.OFPVID_PRESENT: - value = str(value & ~ofproto_v1_3.OFPVID_PRESENT) - else: - value = '0x%04x' % value - return value - - def wrap_dpid_dict(dp, value, to_user=True): if to_user: return {str(dp.id): value} diff --git a/ryu/lib/ofctl_v1_4.py b/ryu/lib/ofctl_v1_4.py index ca1ff3e1..a80020af 100644 --- a/ryu/lib/ofctl_v1_4.py +++ b/ryu/lib/ofctl_v1_4.py @@ -15,8 +15,6 @@ import base64 import logging -import netaddr -import six from ryu.ofproto import ether from ryu.ofproto import ofproto_v1_4 @@ -33,66 +31,8 @@ UTIL = ofctl_utils.OFCtlUtil(ofproto_v1_4) def to_action(dp, dic): ofp = dp.ofproto parser = dp.ofproto_parser - action_type = dic.get('type') - - if action_type == 'OUTPUT': - out_port = UTIL.ofp_port_from_user(dic.get('port', ofp.OFPP_ANY)) - max_len = UTIL.ofp_cml_from_user(dic.get('max_len', ofp.OFPCML_MAX)) - action = parser.OFPActionOutput(out_port, max_len) - elif action_type == 'COPY_TTL_OUT': - action = parser.OFPActionCopyTtlOut() - elif action_type == 'COPY_TTL_IN': - action = parser.OFPActionCopyTtlIn() - elif action_type == 'SET_MPLS_TTL': - mpls_ttl = int(dic.get('mpls_ttl')) - action = parser.OFPActionSetMplsTtl(mpls_ttl) - elif action_type == 'DEC_MPLS_TTL': - action = parser.OFPActionDecMplsTtl() - elif action_type == 'PUSH_VLAN': - ethertype = int(dic.get('ethertype')) - action = parser.OFPActionPushVlan(ethertype) - elif action_type == 'POP_VLAN': - action = parser.OFPActionPopVlan() - elif action_type == 'PUSH_MPLS': - ethertype = int(dic.get('ethertype')) - action = parser.OFPActionPushMpls(ethertype) - elif action_type == 'POP_MPLS': - ethertype = int(dic.get('ethertype')) - action = parser.OFPActionPopMpls(ethertype) - elif action_type == 'SET_QUEUE': - queue_id = UTIL.ofp_queue_from_user(dic.get('queue_id')) - action = parser.OFPActionSetQueue(queue_id) - elif action_type == 'GROUP': - group_id = UTIL.ofp_group_from_user(dic.get('group_id')) - action = parser.OFPActionGroup(group_id) - elif action_type == 'SET_NW_TTL': - nw_ttl = int(dic.get('nw_ttl')) - action = parser.OFPActionSetNwTtl(nw_ttl) - elif action_type == 'DEC_NW_TTL': - action = parser.OFPActionDecNwTtl() - elif action_type == 'SET_FIELD': - field = dic.get('field') - value = dic.get('value') - action = parser.OFPActionSetField(**{field: value}) - elif action_type == 'PUSH_PBB': - ethertype = int(dic.get('ethertype')) - action = parser.OFPActionPushPbb(ethertype) - elif action_type == 'POP_PBB': - action = parser.OFPActionPopPbb() - elif action_type == 'EXPERIMENTER': - experimenter = int(dic.get('experimenter')) - data_type = dic.get('data_type', 'ascii') - if data_type != 'ascii' and data_type != 'base64': - LOG.error('Unknown data type: %s', data_type) - data = dic.get('data', '') - if data_type == 'base64': - data = base64.b64decode(data) - action = parser.OFPActionExperimenterUnknown(experimenter, data) - else: - action = None - - return action + return ofctl_utils.to_action(dic, ofp, parser, action_type, UTIL) def _get_actions(dp, dics): @@ -205,17 +145,17 @@ def instructions_to_str(instructions): def to_match(dp, attrs): convert = {'in_port': UTIL.ofp_port_from_user, 'in_phy_port': int, - 'metadata': to_match_masked_int, - 'eth_dst': to_match_eth, - 'eth_src': to_match_eth, + 'metadata': ofctl_utils.to_match_masked_int, + 'eth_dst': ofctl_utils.to_match_eth, + 'eth_src': ofctl_utils.to_match_eth, 'eth_type': int, - 'vlan_vid': to_match_vid, + 'vlan_vid': ofctl_utils.to_match_vid, 'vlan_pcp': int, 'ip_dscp': int, 'ip_ecn': int, 'ip_proto': int, - 'ipv4_src': to_match_ip, - 'ipv4_dst': to_match_ip, + 'ipv4_src': ofctl_utils.to_match_ip, + 'ipv4_dst': ofctl_utils.to_match_ip, 'tcp_src': int, 'tcp_dst': int, 'udp_src': int, @@ -225,24 +165,24 @@ def to_match(dp, attrs): 'icmpv4_type': int, 'icmpv4_code': int, 'arp_op': int, - 'arp_spa': to_match_ip, - 'arp_tpa': to_match_ip, - 'arp_sha': to_match_eth, - 'arp_tha': to_match_eth, - 'ipv6_src': to_match_ip, - 'ipv6_dst': to_match_ip, + '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': int, 'icmpv6_type': int, 'icmpv6_code': int, - 'ipv6_nd_target': to_match_ip, - 'ipv6_nd_sll': to_match_eth, - 'ipv6_nd_tll': to_match_eth, + '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': int, 'mpls_tc': int, 'mpls_bos': int, - 'pbb_isid': to_match_masked_int, - 'tunnel_id': to_match_masked_int, - 'ipv6_exthdr': to_match_masked_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} if attrs.get('eth_type') == ether.ETH_TYPE_ARP: if 'ipv4_src' in attrs and 'arp_spa' not in attrs: @@ -263,55 +203,8 @@ def to_match(dp, attrs): return dp.ofproto_parser.OFPMatch(**kwargs) -def to_match_eth(value): - if '/' in value: - value = value.split('/') - return value[0], value[1] - else: - return value - - -def to_match_ip(value): - if '/' in value: - (ip_addr, ip_mask) = value.split('/') - if ip_mask.isdigit(): - ip = netaddr.ip.IPNetwork(value) - ip_addr = str(ip.ip) - ip_mask = str(ip.netmask) - return ip_addr, ip_mask - else: - return value - - def to_match_vid(value): - # NOTE: If "vlan_id" field is described as decimal int value - # (and decimal string value), it is treated as values of - # VLAN tag, and OFPVID_PRESENT(0x1000) bit is automatically - # applied. OTOH, If it is described as hexadecimal string, - # treated as values of oxm_value (including OFPVID_PRESENT - # bit), and OFPVID_PRESENT bit is NOT automatically applied. - if isinstance(value, six.integer_types): - # described as decimal int value - return value | ofproto_v1_4.OFPVID_PRESENT - else: - if '/' in value: - val = value.split('/') - return int(val[0], 0), int(val[1], 0) - else: - if value.isdigit(): - # described as decimal string value - return int(value, 10) | ofproto_v1_4.OFPVID_PRESENT - else: - return int(value, 0) - - -def to_match_masked_int(value): - if isinstance(value, str) and '/' in value: - value = value.split('/') - return (ofctl_utils.str_to_int(value[0]), - ofctl_utils.str_to_int(value[1])) - else: - return ofctl_utils.str_to_int(value) + return ofctl_utils.to_match_vid(value, ofproto_v1_4.OFPVID_PRESENT) def match_to_str(ofmatch): @@ -325,7 +218,8 @@ def match_to_str(ofmatch): mask = match_field['OXMTlv']['mask'] value = match_field['OXMTlv']['value'] if key == 'vlan_vid': - value = match_vid_to_str(value, mask) + value = ofctl_utils.match_vid_to_str(value, mask, + ofproto_v1_4.OFPVID_PRESENT) elif key == 'in_port': value = UTIL.ofp_port_to_user(value) else: @@ -336,17 +230,6 @@ def match_to_str(ofmatch): return match -def match_vid_to_str(value, mask): - if mask is not None: - value = '0x%04x/0x%04x' % (value, mask) - else: - if value & ofproto_v1_4.OFPVID_PRESENT: - value = str(value & ~ofproto_v1_4.OFPVID_PRESENT) - else: - value = '0x%04x' % value - return value - - def get_desc_stats(dp, waiters): stats = dp.ofproto_parser.OFPDescStatsRequest(dp, 0) msgs = [] -- cgit v1.2.3