diff options
author | Yusuke Iwase <iwase.yusuke0@gmail.com> | 2015-10-06 16:48:08 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2015-10-11 21:51:37 +0900 |
commit | 9663fbe5631492d28a0fcf643b6381c15ddbeb45 (patch) | |
tree | 495d6e2327e91797e5437e9531d1328db7bb7e6a | |
parent | c0723eb0a632870a3077c2513aee7ed51cb31779 (diff) |
of10: Support human readable MAC/IPv4 address in OFPMatch
In OF1.0, OFPMatch is required to specify MAC address as a binary
type value and to specify IPv4 Address as an int type value.
This behavior is differ from that in OF1.2+.
This patch makes OFPMatch in OF1.0 enable to support human readable
representation of MAC/IPv4 address like OF1.2+ API.
The current API in OF1.0:
>>> match = parser.OFPMatch(dl_src=b'\x01\x02\x03\x04\x05\x06',
... nw_src=167772163)
>>> match.dl_src
'\x01\x02\x03\x04\x05\x06'
>>> match.nw_src
167772163
The introduced API (the same as OF1.2+ API):
>>> match = parser.OFPMatch(dl_dst='aa:bb:cc:dd:ee:ff',
... nw_dst='192.168.0.1')
>>> match['dl_dst']
'aa:bb:cc:dd:ee:ff'
>>> match['nw_dst']
'192.168.0.1'
Signed-off-by: IWASE Yusuke <iwase.yusuke0@gmail.com>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/lib/ip.py | 72 | ||||
-rw-r--r-- | ryu/ofproto/ofproto_v1_0_parser.py | 23 | ||||
-rw-r--r-- | ryu/tests/unit/ofproto/test_parser_v10.py | 44 |
3 files changed, 97 insertions, 42 deletions
diff --git a/ryu/lib/ip.py b/ryu/lib/ip.py index 10a9abdb..6630418d 100644 --- a/ryu/lib/ip.py +++ b/ryu/lib/ip.py @@ -1,30 +1,66 @@ +# Copyright (C) 2015 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 + from ryu.lib import addrconv def ipv4_to_bin(ip): - ''' - Parse an IP address and return an unsigned int. - The IP address is in dotted decimal notation. - ''' + """ + Converts human readable IPv4 string to binary representation. + :param str ip: IPv4 address string + :return: binary representation of IPv4 address + """ return addrconv.ipv4.text_to_bin(ip) +def ipv4_to_int(ip): + """ + Converts human readable IPv4 string to int type representation. + :param str ip: IPv4 address string w.x.y.z + :returns: unsigned int of form w << 24 | x << 16 | y << 8 | z + """ + return struct.unpack("!I", addrconv.ipv4.text_to_bin(ip))[0] + + def ipv4_to_str(ip): - """Generate IP address string from an unsigned int. - ip: unsigned int of form w << 24 | x << 16 | y << 8 | z - returns: ip address string w.x.y.z""" - return addrconv.ipv4.bin_to_text(ip) + """ + Converts binary or int type representation to human readable IPv4 string. + :param str ip: binary or int type representation of IPv4 address + :return: IPv4 address string + """ + if isinstance(ip, int): + return addrconv.ipv4.bin_to_text(struct.pack("!I", ip)) + else: + return addrconv.ipv4.bin_to_text(ip) -def ipv6_to_bin(ipv6): - ''' - convert ipv6 string to binary representation - ''' - return addrconv.ipv6.text_to_bin(ipv6) +def ipv6_to_bin(ip): + """ + Converts human readable IPv6 string to binary representation. + :param str ip: IPv6 address string + :return: binary representation of IPv6 address + """ + return addrconv.ipv6.text_to_bin(ip) -def ipv6_to_str(bin_addr): - ''' - convert binary representation to human readable string - ''' - return addrconv.ipv6.bin_to_text(bin_addr) +def ipv6_to_str(ip): + """ + Converts binary representation to human readable IPv6 string. + :param str ip: binary representation of IPv6 address + :return: IPv6 address string + """ + return addrconv.ipv6.bin_to_text(ip) diff --git a/ryu/ofproto/ofproto_v1_0_parser.py b/ryu/ofproto/ofproto_v1_0_parser.py index 4b00db1e..73d3409b 100644 --- a/ryu/ofproto/ofproto_v1_0_parser.py +++ b/ryu/ofproto/ofproto_v1_0_parser.py @@ -24,6 +24,7 @@ import six from ryu.ofproto.ofproto_parser import StringifyMixin, MsgBase from ryu.lib import addrconv +from ryu.lib import ip from ryu.lib import mac from ryu.lib.pack_utils import msg_pack_into from ryu.ofproto import ofproto_common @@ -130,6 +131,8 @@ class OFPMatch(StringifyMixin): self.dl_src = mac.DONTCARE else: wc &= ~ofproto.OFPFW_DL_SRC + if isinstance(dl_src, str) and ':' in dl_src: + dl_src = addrconv.mac.text_to_bin(dl_src) if dl_src == 0: self.dl_src = mac.DONTCARE else: @@ -139,6 +142,8 @@ class OFPMatch(StringifyMixin): self.dl_dst = mac.DONTCARE else: wc &= ~ofproto.OFPFW_DL_DST + if isinstance(dl_dst, str) and ':' in dl_dst: + dl_dst = addrconv.mac.text_to_bin(dl_dst) if dl_dst == 0: self.dl_dst = mac.DONTCARE else: @@ -179,6 +184,8 @@ class OFPMatch(StringifyMixin): else: wc &= (32 - nw_src_mask) << ofproto.OFPFW_NW_SRC_SHIFT \ | ~ofproto.OFPFW_NW_SRC_MASK + if isinstance(nw_src, str) and '.' in nw_src: + nw_src = ip.ipv4_to_int(nw_src) self.nw_src = nw_src if nw_dst is None: @@ -186,6 +193,8 @@ class OFPMatch(StringifyMixin): else: wc &= (32 - nw_dst_mask) << ofproto.OFPFW_NW_DST_SHIFT \ | ~ofproto.OFPFW_NW_DST_MASK + if isinstance(nw_dst, str) and '.' in nw_dst: + nw_dst = ip.ipv4_to_int(nw_dst) self.nw_dst = nw_dst if tp_src is None: @@ -219,10 +228,16 @@ class OFPMatch(StringifyMixin): elif name == 'wildcards': return self.wildcards - wc_name = 'OFPFW_' + name.upper() - wc = getattr(ofproto, wc_name, ofproto.OFPFW_ALL) - if self.wildcards & ~wc: - return getattr(self, name) + wc = getattr(ofproto, 'OFPFW_' + name.upper(), 0) + if ~self.wildcards & wc: + value = getattr(self, name) + if isinstance(value, six.binary_type) \ + and name in ['dl_src', 'dl_dst']: + value = addrconv.mac.bin_to_text(value) + elif isinstance(value, int) \ + and name in ['nw_src', 'nw_dst']: + value = ip.ipv4_to_str(value) + return value else: raise KeyError(name) diff --git a/ryu/tests/unit/ofproto/test_parser_v10.py b/ryu/tests/unit/ofproto/test_parser_v10.py index dca2b470..a9c3d639 100644 --- a/ryu/tests/unit/ofproto/test_parser_v10.py +++ b/ryu/tests/unit/ofproto/test_parser_v10.py @@ -105,8 +105,10 @@ class TestOFPMatch(unittest.TestCase): # nw_src, nw_dst, tp_src, tp_dst wildcards = {'buf': b'\xd2\x71\x25\x23', 'val': 3530630435} in_port = {'buf': b'\x37\x8b', 'val': 14219} - dl_src = b'\x52\x54\x54\x10\x20\x99' - dl_dst = b'\x61\x31\x50\x6d\xc9\xe5' + dl_src = {'buf': b'\x52\x54\x54\x10\x20\x99', + 'human': '52:54:54:10:20:99'} + dl_dst = {'buf': b'\x61\x31\x50\x6d\xc9\xe5', + 'human': '61:31:50:6d:c9:e5'} dl_vlan = {'buf': b'\xc1\xf9', 'val': 49657} dl_vlan_pcp = {'buf': b'\x79', 'val': 121} zfill0 = b'\x00' @@ -114,15 +116,17 @@ class TestOFPMatch(unittest.TestCase): nw_tos = {'buf': b'\xde', 'val': 222} nw_proto = {'buf': b'\xe5', 'val': 229} zfil11 = b'\x00' * 2 - nw_src = {'buf': b'\x1b\x6d\x8d\x4b', 'val': 460164427} - nw_dst = {'buf': b'\xab\x25\xe1\x20', 'val': 2871386400} + nw_src = {'buf': b'\x1b\x6d\x8d\x4b', 'val': 460164427, + 'human': '27.109.141.75'} + nw_dst = {'buf': b'\xab\x25\xe1\x20', 'val': 2871386400, + 'human': '171.37.225.32'} tp_src = {'buf': b'\xd5\xc3', 'val': 54723} tp_dst = {'buf': b'\x78\xb9', 'val': 30905} buf = wildcards['buf'] \ + in_port['buf'] \ - + dl_src \ - + dl_dst \ + + dl_src['buf'] \ + + dl_dst['buf'] \ + dl_vlan['buf'] \ + dl_vlan_pcp['buf'] \ + zfill0 \ @@ -158,12 +162,12 @@ class TestOFPMatch(unittest.TestCase): pass def test_init(self): - c = self._get_obj(self.dl_src, self.dl_dst) + c = self._get_obj(self.dl_src['buf'], self.dl_dst['buf']) eq_(self.wildcards['val'], c.wildcards) eq_(self.in_port['val'], c.in_port) - eq_(self.dl_src, c.dl_src) - eq_(self.dl_dst, c.dl_dst) + eq_(self.dl_src['buf'], c.dl_src) + eq_(self.dl_dst['buf'], c.dl_dst) eq_(self.dl_vlan['val'], c.dl_vlan) eq_(self.dl_vlan_pcp['val'], c.dl_vlan_pcp) eq_(self.dl_type['val'], c.dl_type) @@ -180,13 +184,13 @@ class TestOFPMatch(unittest.TestCase): eq_(mac.DONTCARE, c.dl_dst) def test_parse(self): - c = self._get_obj(self.dl_src, self.dl_dst) + c = self._get_obj(self.dl_src['buf'], self.dl_dst['buf']) res = c.parse(self.buf, 0) eq_(self.wildcards['val'], res.wildcards) eq_(self.in_port['val'], res.in_port) - eq_(self.dl_src, res.dl_src) - eq_(self.dl_dst, res.dl_dst) + eq_(self.dl_src['buf'], res.dl_src) + eq_(self.dl_dst['buf'], res.dl_dst) eq_(self.dl_vlan['val'], res.dl_vlan) eq_(self.dl_vlan_pcp['val'], res.dl_vlan_pcp) eq_(self.dl_type['val'], res.dl_type) @@ -199,7 +203,7 @@ class TestOFPMatch(unittest.TestCase): def test_serialize(self): buf = bytearray() - c = self._get_obj(self.dl_src, self.dl_dst) + c = self._get_obj(self.dl_src['buf'], self.dl_dst['buf']) c.serialize(buf, 0) @@ -208,8 +212,8 @@ class TestOFPMatch(unittest.TestCase): eq_(self.wildcards['val'], res[0]) eq_(self.in_port['val'], res[1]) - eq_(self.dl_src, res[2]) - eq_(self.dl_dst, res[3]) + eq_(self.dl_src['buf'], res[2]) + eq_(self.dl_dst['buf'], res[3]) eq_(self.dl_vlan['val'], res[4]) eq_(self.dl_vlan_pcp['val'], res[5]) eq_(self.dl_type['val'], res[6]) @@ -221,19 +225,19 @@ class TestOFPMatch(unittest.TestCase): eq_(self.tp_dst['val'], res[12]) def test_getitem(self): - c = self._get_obj(self.dl_src, self.dl_dst) + c = self._get_obj(self.dl_src['buf'], self.dl_dst['buf']) eq_(self.wildcards['val'], c["wildcards"]) eq_(self.in_port['val'], c["in_port"]) - eq_(self.dl_src, c["dl_src"]) - eq_(self.dl_dst, c["dl_dst"]) + eq_(self.dl_src['human'], c["dl_src"]) + eq_(self.dl_dst['human'], c["dl_dst"]) eq_(self.dl_vlan['val'], c["dl_vlan"]) eq_(self.dl_vlan_pcp['val'], c["dl_vlan_pcp"]) eq_(self.dl_type['val'], c["dl_type"]) eq_(self.nw_tos['val'], c["nw_tos"]) eq_(self.nw_proto['val'], c["nw_proto"]) - eq_(self.nw_src['val'], c["nw_src"]) - eq_(self.nw_dst['val'], c["nw_dst"]) + eq_(self.nw_src['human'], c["nw_src"]) + eq_(self.nw_dst['human'], c["nw_dst"]) eq_(self.tp_src['val'], c["tp_src"]) eq_(self.tp_dst['val'], c["tp_dst"]) |