backing up
[vsorcdistro/.git] / ryu / build / lib.linux-armv7l-2.7 / ryu / ofproto / oxx_fields.py
1 # Copyright (C) 2015 Nippon Telegraph and Telephone Corporation.
2 #
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
6 #
7 #    http://www.apache.org/licenses/LICENSE-2.0
8 #
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
12 # implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16 # there are two representations of value and mask this module deal with.
17 #
18 # "user"
19 #   (value, mask) or value.  the latter means no mask.
20 #   value and mask are strings.
21 #
22 # "internal"
23 #   value and mask are on-wire bytes.
24 #   mask is None if no mask.
25
26 import six
27 import struct
28
29 from ryu.ofproto import ofproto_common
30 from ryu.lib.pack_utils import msg_pack_into
31 from ryu.lib import type_desc
32
33 if six.PY3:
34     _ord = int
35 else:
36     _ord = ord
37
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
41
42
43 def _get_field_info_by_name(oxx, name_to_field, name):
44     try:
45         f = name_to_field[name]
46         t = f.type
47         num = f.num
48     except KeyError:
49         t = type_desc.UnknownType
50         if name.startswith('field_'):
51             num = int(name.split('_')[1])
52         else:
53             raise KeyError('unknown %s field: %s' % (oxx.upper(), name))
54     return num, t
55
56
57 def _from_user_header(oxx, name_to_field, name):
58     (num, t) = _get_field_info_by_name(oxx, name_to_field, name)
59     return num
60
61
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
68     else:
69         value = user_value
70         mask = None
71     if value is not None:
72         value = t.from_user(value)
73     if mask is not None:
74         mask = t.from_user(mask)
75     elif isinstance(value, tuple):
76         # This hack is to accomodate CIDR notations with IPv[46]Addr.
77         value, mask = value
78     return num, value, mask
79
80
81 def _get_field_info_by_number(oxx, num_to_field, n):
82     try:
83         f = num_to_field[n]
84         t = f.type
85         name = f.name
86     except KeyError:
87         t = type_desc.UnknownType
88         if isinstance(n, six.integer_types):
89             name = 'field_%d' % (n,)
90         else:
91             raise KeyError('unknown %s field number: %s' % (oxx.upper(), n))
92     return name, t
93
94
95 def _to_user_header(oxx, num_to_field, n):
96     (name, t) = _get_field_info_by_number(oxx, num_to_field, n)
97     return name
98
99
100 def _to_user(oxx, num_to_field, n, v, m):
101     (name, t) = _get_field_info_by_number(oxx, num_to_field, n)
102     if v is not None:
103         if isinstance(v, (tuple, list)):
104             v_len = len(v) * len(v[0])
105         else:
106             v_len = len(v)
107         if hasattr(t, 'size') and t.size != v_len:
108             raise Exception(
109                 'Unexpected %s payload length %d for %s (expected %d)'
110                 % (oxx.upper(), v_len, name, t.size))
111         value = t.to_user(v)
112     else:
113         value = None
114     if m is None:
115         user_value = value
116     else:
117         user_value = (value, t.to_user(m))
118     return name, user_value
119
120
121 def _field_desc(num_to_field, n):
122     return num_to_field[n]
123
124
125 def _normalize_user(oxx, mod, k, uv):
126     try:
127         from_user = getattr(mod, oxx + '_from_user')
128         (n, v, m) = from_user(k, uv)
129     except:
130         return (k, uv)
131     # apply mask
132     if m is not None:
133         v = b''.join(six.int2byte(_ord(x) & _ord(y)) for (x, y) in zip(v, m))
134     try:
135         to_user = getattr(mod, oxx + '_to_user')
136         (k2, uv2) = to_user(n, v, m)
137     except:
138         return (k, uv)
139     assert k2 == k
140     return (k2, uv2)
141
142
143 def _parse_header_impl(mod, buf, offset):
144     hdr_pack_str = '!I'
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,
156                                         offset + hdr_len)
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:
161             # XXX
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)
169         else:
170             num = (exp_id, oxx_type)
171     else:
172         num = oxx_type
173         exp_hdr_len = 0
174     value_len = oxx_length - exp_hdr_len
175     if oxm_hasmask:
176         value_len //= 2
177     assert value_len > 0
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
181
182
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
187
188
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)
198     if hasmask:
199         (mask, ) = struct.unpack_from(value_pack_str, buf,
200                                       value_offset + value_len)
201     else:
202         mask = None
203     return oxx_type_num, value, mask, field_len
204
205
206 def _make_exp_hdr(oxx, mod, n):
207     exp_hdr = bytearray()
208     try:
209         get_desc = getattr(mod, '_' + oxx + '_field_desc')
210         desc = get_desc(n)
211     except KeyError:
212         return n, exp_hdr
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:
218             # XXX
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)
223         else:
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)
229         n = oxx_type
230         assert (n >> 7) == OFPXXC_EXPERIMENTER
231     return n, exp_hdr
232
233
234 def _serialize_header(oxx, mod, n, buf, offset):
235     try:
236         get_desc = getattr(mod, '_' + oxx + '_field_desc')
237         desc = get_desc(n)
238         value_len = desc.type.size
239     except KeyError:
240         value_len = 0
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),
246                   bytes(exp_hdr))
247     return struct.calcsize(pack_str)
248
249
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)
254     if mask:
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)
260     else:
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)