1# Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 2# Copyright (C) 2015 YAMAMOTO Takashi <yamamoto at valinux co jp> 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13# implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17import base64 18 19import six 20 21from ryu.lib import addrconv 22 23 24class TypeDescr(object): 25 pass 26 27 28class IntDescr(TypeDescr): 29 def __init__(self, size): 30 self.size = size 31 32 def to_user(self, binary): 33 i = 0 34 for _ in range(self.size): 35 c = binary[:1] 36 i = i * 256 + ord(c) 37 binary = binary[1:] 38 return i 39 40 def from_user(self, i): 41 binary = b'' 42 for _ in range(self.size): 43 binary = six.int2byte(i & 255) + binary 44 i //= 256 45 return binary 46 47 48Int1 = IntDescr(1) 49Int2 = IntDescr(2) 50Int3 = IntDescr(3) 51Int4 = IntDescr(4) 52Int8 = IntDescr(8) 53Int9 = IntDescr(9) 54Int16 = IntDescr(16) 55 56 57def _split_str(s, n): 58 """ 59 split string into list of strings by specified number. 60 """ 61 length = len(s) 62 return [s[i:i + n] for i in range(0, length, n)] 63 64 65class IntDescrMlt(TypeDescr): 66 def __init__(self, length, num): 67 self.length = length 68 self.num = num 69 self.size = length * num 70 71 def to_user(self, binary): 72 assert len(binary) == self.size 73 lb = _split_str(binary, self.length) 74 li = [] 75 for b in lb: 76 i = 0 77 for _ in range(self.length): 78 c = b[:1] 79 i = i * 256 + ord(c) 80 b = b[1:] 81 li.append(i) 82 return tuple(li) 83 84 def from_user(self, li): 85 assert len(li) == self.num 86 binary = b'' 87 for i in li: 88 b = b'' 89 for _ in range(self.length): 90 b = six.int2byte(i & 255) + b 91 i //= 256 92 binary += b 93 return binary 94 95 96Int4Double = IntDescrMlt(4, 2) 97 98 99class MacAddr(TypeDescr): 100 size = 6 101 to_user = addrconv.mac.bin_to_text 102 from_user = addrconv.mac.text_to_bin 103 104 105class IPv4Addr(TypeDescr): 106 size = 4 107 to_user = addrconv.ipv4.bin_to_text 108 from_user = addrconv.ipv4.text_to_bin 109 110 111class IPv6Addr(TypeDescr): 112 size = 16 113 to_user = addrconv.ipv6.bin_to_text 114 from_user = addrconv.ipv6.text_to_bin 115 116 117class UnknownType(TypeDescr): 118 119 @staticmethod 120 def to_user(data): 121 if six.PY3: 122 return base64.b64encode(data).decode('ascii') 123 else: 124 return base64.b64encode(data) 125 126 from_user = staticmethod(base64.b64decode) 127 128 129class TypeDisp(object): 130 _TYPES = {} 131 _REV_TYPES = None 132 _UNKNOWN_TYPE = None 133 134 @classmethod 135 def register_unknown_type(cls): 136 def _register_type(subcls): 137 cls._UNKNOWN_TYPE = subcls 138 return subcls 139 return _register_type 140 141 @classmethod 142 def register_type(cls, type_): 143 cls._TYPES = cls._TYPES.copy() 144 145 def _register_type(subcls): 146 cls._TYPES[type_] = subcls 147 cls._REV_TYPES = None 148 return subcls 149 return _register_type 150 151 @classmethod 152 def _lookup_type(cls, type_): 153 try: 154 return cls._TYPES[type_] 155 except KeyError: 156 return cls._UNKNOWN_TYPE 157 158 @classmethod 159 def _rev_lookup_type(cls, targ_cls): 160 if cls._REV_TYPES is None: 161 rev = dict((v, k) for k, v in cls._TYPES.items()) 162 cls._REV_TYPES = rev 163 return cls._REV_TYPES[targ_cls] 164