blob: 02f1c0ec101d769725f3f59faf5a789314a2306e [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 Lanef0bac292013-12-01 15:55:21 -080038def pack_list(values):
39 return "".join([x.pack() for x in values])
40
Rich Lane57026dc2013-05-01 10:13:16 -070041def unpack_list(reader, deserializer):
Rich Lane15cbe842013-04-26 16:04:11 -070042 """
Rich Lane57026dc2013-05-01 10:13:16 -070043 The deserializer function should take an OFReader and return the new object.
Rich Lane15cbe842013-04-26 16:04:11 -070044 """
45 entries = []
Rich Lane57026dc2013-05-01 10:13:16 -070046 while not reader.is_empty():
47 entries.append(deserializer(reader))
Rich Lane15cbe842013-04-26 16:04:11 -070048 return entries
Rich Lane1de06ab2013-04-26 16:58:37 -070049
Rich Lane5a72bc32013-07-23 14:10:21 -070050def pad_to(alignment, length):
51 """
52 Return a string of zero bytes that will pad a string of length 'length' to
53 a multiple of 'alignment'.
54 """
55 return "\x00" * ((length + alignment - 1)/alignment*alignment - length)
56
Rich Lane1de06ab2013-04-26 16:58:37 -070057class OFReader(object):
58 """
59 Cursor over a read-only buffer
60
61 OpenFlow messages are best thought of as a sequence of elements of
62 variable size, rather than a C-style struct with fixed offsets and
63 known field lengths. This class supports efficiently reading
64 fields sequentially and is intended to be used recursively by the
65 parsers of child objects which will implicitly update the offset.
Rich Lane5df3fd82013-12-01 14:53:06 -080066
67 buf: buffer object
68 start: initial position in the buffer
69 length: number of bytes after start
70 offset: distance from start
Rich Lane1de06ab2013-04-26 16:58:37 -070071 """
Rich Lane5df3fd82013-12-01 14:53:06 -080072 def __init__(self, buf, start=0, length=None):
Rich Lane1de06ab2013-04-26 16:58:37 -070073 self.buf = buf
Rich Lane5df3fd82013-12-01 14:53:06 -080074 self.start = start
75 if length is None:
76 self.length = len(buf) - start
77 else:
78 self.length = length
Rich Lane1de06ab2013-04-26 16:58:37 -070079 self.offset = 0
80
81 def read(self, fmt):
82 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -080083 if self.offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -070084 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -080085 result = st.unpack_from(self.buf, self.start+self.offset)
Rich Lane1de06ab2013-04-26 16:58:37 -070086 self.offset += st.size
87 return result
88
89 def read_all(self):
Rich Lane5df3fd82013-12-01 14:53:06 -080090 s = self.buf[(self.start+self.offset):(self.start+self.length)]
91 assert(len(s) == self.length - self.offset)
92 self.offset = self.length
93 return s
Rich Lane1de06ab2013-04-26 16:58:37 -070094
Rich Lane78a3bc42013-11-29 19:22:08 -080095 def peek(self, fmt, offset=0):
Rich Lane1de06ab2013-04-26 16:58:37 -070096 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -080097 if self.offset + offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -070098 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -080099 result = st.unpack_from(self.buf, self.start + self.offset + offset)
Rich Lane1de06ab2013-04-26 16:58:37 -0700100 return result
101
102 def skip(self, length):
Rich Lane5df3fd82013-12-01 14:53:06 -0800103 if self.offset + length > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700104 raise loxi.ProtocolError("Buffer too short")
105 self.offset += length
106
Rich Laneb564efc2013-07-23 14:19:29 -0700107 def skip_align(self):
Rich Laneef876aa2014-12-10 16:33:42 -0800108 new_offset = (self.offset + 7) / 8 * 8
Rich Lane5df3fd82013-12-01 14:53:06 -0800109 if new_offset > self.length:
Rich Laneb564efc2013-07-23 14:19:29 -0700110 raise loxi.ProtocolError("Buffer too short")
111 self.offset = new_offset
112
Rich Lane1de06ab2013-04-26 16:58:37 -0700113 def is_empty(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800114 return self.offset == self.length
Rich Lane1de06ab2013-04-26 16:58:37 -0700115
Rich Lane5df3fd82013-12-01 14:53:06 -0800116 # Used when parsing objects that have their own length fields
Rich Laneef876aa2014-12-10 16:33:42 -0800117 def slice(self, length, rewind=0):
118 if self.offset + length - rewind > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700119 raise loxi.ProtocolError("Buffer too short")
Rich Laneef876aa2014-12-10 16:33:42 -0800120 reader = OFReader(self.buf, self.start + self.offset - rewind, length)
121 reader.skip(rewind)
122 self.offset += length - rewind
Rich Lane5df3fd82013-12-01 14:53:06 -0800123 return reader