1 # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 # there are two representations of value and mask this module deal with.
19 # (value, mask) or value. the latter means no mask.
20 # value and mask are strings.
23 # value and mask are on-wire bytes.
24 # mask is None if no mask.
29 from ryu.ofproto import ofproto_common
30 from ryu.lib.pack_utils import msg_pack_into
31 from ryu.lib import type_desc
38 # 'OFPXXC_EXPERIMENTER' has not corresponding field in the specification.
39 # This is transparently value for Experimenter class ID for OXM/OXS.
40 OFPXXC_EXPERIMENTER = 0xffff
43 def _get_field_info_by_name(oxx, name_to_field, name):
45 f = name_to_field[name]
49 t = type_desc.UnknownType
50 if name.startswith('field_'):
51 num = int(name.split('_')[1])
53 raise KeyError('unknown %s field: %s' % (oxx.upper(), name))
57 def _from_user_header(oxx, name_to_field, name):
58 (num, t) = _get_field_info_by_name(oxx, name_to_field, name)
62 def _from_user(oxx, name_to_field, name, user_value):
63 (num, t) = _get_field_info_by_name(oxx, name_to_field, name)
64 # the 'list' case below is a bit hack; json.dumps silently maps
65 # python tuples into json lists.
66 if oxx == 'oxm' and isinstance(user_value, (tuple, list)):
67 (value, mask) = user_value
72 value = t.from_user(value)
74 mask = t.from_user(mask)
75 elif isinstance(value, tuple):
76 # This hack is to accomodate CIDR notations with IPv[46]Addr.
78 return num, value, mask
81 def _get_field_info_by_number(oxx, num_to_field, n):
87 t = type_desc.UnknownType
88 if isinstance(n, six.integer_types):
89 name = 'field_%d' % (n,)
91 raise KeyError('unknown %s field number: %s' % (oxx.upper(), n))
95 def _to_user_header(oxx, num_to_field, n):
96 (name, t) = _get_field_info_by_number(oxx, num_to_field, n)
100 def _to_user(oxx, num_to_field, n, v, m):
101 (name, t) = _get_field_info_by_number(oxx, num_to_field, n)
103 if isinstance(v, (tuple, list)):
104 v_len = len(v) * len(v[0])
107 if hasattr(t, 'size') and t.size != v_len:
109 'Unexpected %s payload length %d for %s (expected %d)'
110 % (oxx.upper(), v_len, name, t.size))
117 user_value = (value, t.to_user(m))
118 return name, user_value
121 def _field_desc(num_to_field, n):
122 return num_to_field[n]
125 def _normalize_user(oxx, mod, k, uv):
127 from_user = getattr(mod, oxx + '_from_user')
128 (n, v, m) = from_user(k, uv)
133 v = b''.join(six.int2byte(_ord(x) & _ord(y)) for (x, y) in zip(v, m))
135 to_user = getattr(mod, oxx + '_to_user')
136 (k2, uv2) = to_user(n, v, m)
143 def _parse_header_impl(mod, buf, offset):
145 (header, ) = struct.unpack_from(hdr_pack_str, buf, offset)
146 hdr_len = struct.calcsize(hdr_pack_str)
147 oxx_type = header >> 9 # class|field
148 oxm_hasmask = mod.oxm_tlv_header_extract_hasmask(header)
149 oxx_class = oxx_type >> 7
150 oxx_length = header & 0xff
151 if oxx_class == OFPXXC_EXPERIMENTER:
152 # Experimenter OXMs/OXSs have 64-bit header.
153 # (vs 32-bit for other OXMs/OXSs)
154 exp_hdr_pack_str = '!I' # experimenter_id
155 (exp_id, ) = struct.unpack_from(exp_hdr_pack_str, buf,
157 exp_hdr_len = struct.calcsize(exp_hdr_pack_str)
158 assert exp_hdr_len == 4
159 oxx_field = oxx_type & 0x7f
160 if exp_id == ofproto_common.ONF_EXPERIMENTER_ID and oxx_field == 0:
162 # This block implements EXT-256 style experimenter OXM.
163 onf_exp_type_pack_str = '!H'
164 (exp_type, ) = struct.unpack_from(onf_exp_type_pack_str, buf,
165 offset + hdr_len + exp_hdr_len)
166 exp_hdr_len += struct.calcsize(onf_exp_type_pack_str)
167 assert exp_hdr_len == 4 + 2
168 num = (exp_id, exp_type)
170 num = (exp_id, oxx_type)
174 value_len = oxx_length - exp_hdr_len
178 field_len = hdr_len + oxx_length
179 total_hdr_len = hdr_len + exp_hdr_len
180 return num, total_hdr_len, oxm_hasmask, value_len, field_len
183 def _parse_header(mod, buf, offset):
184 (oxx_type_num, total_hdr_len, hasmask, value_len,
185 field_len) = _parse_header_impl(mod, buf, offset)
186 return oxx_type_num, field_len - value_len
189 def _parse(mod, buf, offset):
190 (oxx_type_num, total_hdr_len, hasmask, value_len,
191 field_len) = _parse_header_impl(mod, buf, offset)
192 # Note: OXM/OXS payload length (oxx_len) includes Experimenter ID
193 # (exp_hdr_len) for experimenter OXMs/OXSs.
194 value_offset = offset + total_hdr_len
195 value_pack_str = '!%ds' % value_len
196 assert struct.calcsize(value_pack_str) == value_len
197 (value, ) = struct.unpack_from(value_pack_str, buf, value_offset)
199 (mask, ) = struct.unpack_from(value_pack_str, buf,
200 value_offset + value_len)
203 return oxx_type_num, value, mask, field_len
206 def _make_exp_hdr(oxx, mod, n):
207 exp_hdr = bytearray()
209 get_desc = getattr(mod, '_' + oxx + '_field_desc')
213 if desc._class == OFPXXC_EXPERIMENTER:
214 (exp_id, exp_type) = n
215 assert desc.experimenter_id == exp_id
216 oxx_type = getattr(desc, oxx + '_type')
217 if desc.exp_type == 2560:
219 # This block implements EXT-256 style experimenter OXM.
220 exp_hdr_pack_str = '!IH' # experimenter_id, exp_type
221 msg_pack_into(exp_hdr_pack_str, exp_hdr, 0,
222 desc.experimenter_id, desc.exp_type)
224 assert oxx_type == exp_type | (OFPXXC_EXPERIMENTER << 7)
225 exp_hdr_pack_str = '!I' # experimenter_id
226 msg_pack_into(exp_hdr_pack_str, exp_hdr, 0,
227 desc.experimenter_id)
228 assert len(exp_hdr) == struct.calcsize(exp_hdr_pack_str)
230 assert (n >> 7) == OFPXXC_EXPERIMENTER
234 def _serialize_header(oxx, mod, n, buf, offset):
236 get_desc = getattr(mod, '_' + oxx + '_field_desc')
238 value_len = desc.type.size
241 n, exp_hdr = _make_exp_hdr(oxx, mod, n)
242 exp_hdr_len = len(exp_hdr)
243 pack_str = "!I%ds" % (exp_hdr_len,)
244 msg_pack_into(pack_str, buf, offset,
245 (n << 9) | (0 << 8) | (exp_hdr_len + value_len),
247 return struct.calcsize(pack_str)
250 def _serialize(oxx, mod, n, value, mask, buf, offset):
251 n, exp_hdr = _make_exp_hdr(oxx, mod, n)
252 exp_hdr_len = len(exp_hdr)
253 value_len = len(value)
255 assert value_len == len(mask)
256 pack_str = "!I%ds%ds%ds" % (exp_hdr_len, value_len, len(mask))
257 msg_pack_into(pack_str, buf, offset,
258 (n << 9) | (1 << 8) | (exp_hdr_len + value_len * 2),
259 bytes(exp_hdr), value, mask)
261 pack_str = "!I%ds%ds" % (exp_hdr_len, value_len,)
262 msg_pack_into(pack_str, buf, offset,
263 (n << 9) | (0 << 8) | (exp_hdr_len + value_len),
264 bytes(exp_hdr), value)
265 return struct.calcsize(pack_str)