blob: 99840eca48ea8b158c35c3587ffbd0105297371d [file] [log] [blame]
Rich Lane15cbe842013-04-26 16:04:11 -07001:: # Copyright 2013, Big Switch Networks, Inc.
2:: #
3:: # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with
4:: # the following special exception:
5:: #
6:: # LOXI Exception
7:: #
8:: # As a special exception to the terms of the EPL, you may distribute libraries
9:: # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided
10:: # that copyright and licensing notices generated by LoxiGen are not altered or removed
11:: # from the LoxiGen Libraries and the notice provided below is (i) included in
12:: # the LoxiGen Libraries, if distributed in source code form and (ii) included in any
13:: # documentation for the LoxiGen Libraries, if distributed in binary form.
14:: #
15:: # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler."
16:: #
17:: # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain
18:: # a copy of the EPL at:
19:: #
20:: # http://www.eclipse.org/legal/epl-v10.html
21:: #
22:: # Unless required by applicable law or agreed to in writing, software
23:: # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
24:: # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
25:: # EPL for the specific language governing permissions and limitations
26:: # under the EPL.
27::
28:: include('_copyright.py')
29"""
30Utility functions independent of the protocol version
31"""
32
33:: include('_autogen.py')
34
35import loxi
36import struct
37
Rich Lane57026dc2013-05-01 10:13:16 -070038def unpack_list(reader, deserializer):
Rich Lane15cbe842013-04-26 16:04:11 -070039 """
Rich Lane57026dc2013-05-01 10:13:16 -070040 The deserializer function should take an OFReader and return the new object.
Rich Lane15cbe842013-04-26 16:04:11 -070041 """
42 entries = []
Rich Lane57026dc2013-05-01 10:13:16 -070043 while not reader.is_empty():
44 entries.append(deserializer(reader))
Rich Lane15cbe842013-04-26 16:04:11 -070045 return entries
Rich Lane1de06ab2013-04-26 16:58:37 -070046
Rich Lane5a72bc32013-07-23 14:10:21 -070047def pad_to(alignment, length):
48 """
49 Return a string of zero bytes that will pad a string of length 'length' to
50 a multiple of 'alignment'.
51 """
52 return "\x00" * ((length + alignment - 1)/alignment*alignment - length)
53
Rich Lane1de06ab2013-04-26 16:58:37 -070054class OFReader(object):
55 """
56 Cursor over a read-only buffer
57
58 OpenFlow messages are best thought of as a sequence of elements of
59 variable size, rather than a C-style struct with fixed offsets and
60 known field lengths. This class supports efficiently reading
61 fields sequentially and is intended to be used recursively by the
62 parsers of child objects which will implicitly update the offset.
Rich Lane5df3fd82013-12-01 14:53:06 -080063
64 buf: buffer object
65 start: initial position in the buffer
66 length: number of bytes after start
67 offset: distance from start
Rich Lane1de06ab2013-04-26 16:58:37 -070068 """
Rich Lane5df3fd82013-12-01 14:53:06 -080069 def __init__(self, buf, start=0, length=None):
Rich Lane1de06ab2013-04-26 16:58:37 -070070 self.buf = buf
Rich Lane5df3fd82013-12-01 14:53:06 -080071 self.start = start
72 if length is None:
73 self.length = len(buf) - start
74 else:
75 self.length = length
Rich Lane1de06ab2013-04-26 16:58:37 -070076 self.offset = 0
77
78 def read(self, fmt):
79 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -080080 if self.offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -070081 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -080082 result = st.unpack_from(self.buf, self.start+self.offset)
Rich Lane1de06ab2013-04-26 16:58:37 -070083 self.offset += st.size
84 return result
85
86 def read_all(self):
Rich Lane5df3fd82013-12-01 14:53:06 -080087 s = self.buf[(self.start+self.offset):(self.start+self.length)]
88 assert(len(s) == self.length - self.offset)
89 self.offset = self.length
90 return s
Rich Lane1de06ab2013-04-26 16:58:37 -070091
Rich Lane78a3bc42013-11-29 19:22:08 -080092 def peek(self, fmt, offset=0):
Rich Lane1de06ab2013-04-26 16:58:37 -070093 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -080094 if self.offset + offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -070095 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -080096 result = st.unpack_from(self.buf, self.start + self.offset + offset)
Rich Lane1de06ab2013-04-26 16:58:37 -070097 return result
98
99 def skip(self, length):
Rich Lane5df3fd82013-12-01 14:53:06 -0800100 if self.offset + length > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700101 raise loxi.ProtocolError("Buffer too short")
102 self.offset += length
103
Rich Laneb564efc2013-07-23 14:19:29 -0700104 def skip_align(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800105 new_offset = ((self.start + self.offset + 7) / 8 * 8) - self.start
106 if new_offset > self.length:
Rich Laneb564efc2013-07-23 14:19:29 -0700107 raise loxi.ProtocolError("Buffer too short")
108 self.offset = new_offset
109
Rich Lane1de06ab2013-04-26 16:58:37 -0700110 def is_empty(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800111 return self.offset == self.length
Rich Lane1de06ab2013-04-26 16:58:37 -0700112
Rich Lane5df3fd82013-12-01 14:53:06 -0800113 # Used when parsing objects that have their own length fields
Rich Lane1de06ab2013-04-26 16:58:37 -0700114 def slice(self, length):
Rich Lane5df3fd82013-12-01 14:53:06 -0800115 if self.offset + length > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700116 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -0800117 reader = OFReader(self.buf, self.start + self.offset, length)
Rich Lane1de06ab2013-04-26 16:58:37 -0700118 self.offset += length
Rich Lane5df3fd82013-12-01 14:53:06 -0800119 return reader