blob: 89b158d9e7da271a2663d11a4ffa9fdaf363971c [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 Lane57026dc2013-05-01 10:13:16 -070047def unpack_list_lv16(reader, deserializer):
48 """
49 The deserializer function should take an OFReader and return the new object.
50 """
51 def wrapper(reader):
52 length, = reader.peek('!H')
53 return deserializer(reader.slice(length))
54 return unpack_list(reader, wrapper)
55
56def unpack_list_tlv16(reader, deserializer):
57 """
58 The deserializer function should take an OFReader and an integer type
59 and return the new object.
60 """
61 def wrapper(reader):
62 typ, length, = reader.peek('!HH')
63 return deserializer(reader.slice(length), typ)
64 return unpack_list(reader, wrapper)
65
Rich Lane5a72bc32013-07-23 14:10:21 -070066def pad_to(alignment, length):
67 """
68 Return a string of zero bytes that will pad a string of length 'length' to
69 a multiple of 'alignment'.
70 """
71 return "\x00" * ((length + alignment - 1)/alignment*alignment - length)
72
Rich Lane1de06ab2013-04-26 16:58:37 -070073class OFReader(object):
74 """
75 Cursor over a read-only buffer
76
77 OpenFlow messages are best thought of as a sequence of elements of
78 variable size, rather than a C-style struct with fixed offsets and
79 known field lengths. This class supports efficiently reading
80 fields sequentially and is intended to be used recursively by the
81 parsers of child objects which will implicitly update the offset.
Rich Lane5df3fd82013-12-01 14:53:06 -080082
83 buf: buffer object
84 start: initial position in the buffer
85 length: number of bytes after start
86 offset: distance from start
Rich Lane1de06ab2013-04-26 16:58:37 -070087 """
Rich Lane5df3fd82013-12-01 14:53:06 -080088 def __init__(self, buf, start=0, length=None):
Rich Lane1de06ab2013-04-26 16:58:37 -070089 self.buf = buf
Rich Lane5df3fd82013-12-01 14:53:06 -080090 self.start = start
91 if length is None:
92 self.length = len(buf) - start
93 else:
94 self.length = length
Rich Lane1de06ab2013-04-26 16:58:37 -070095 self.offset = 0
96
97 def read(self, fmt):
98 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -080099 if self.offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700100 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -0800101 result = st.unpack_from(self.buf, self.start+self.offset)
Rich Lane1de06ab2013-04-26 16:58:37 -0700102 self.offset += st.size
103 return result
104
105 def read_all(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800106 s = self.buf[(self.start+self.offset):(self.start+self.length)]
107 assert(len(s) == self.length - self.offset)
108 self.offset = self.length
109 return s
Rich Lane1de06ab2013-04-26 16:58:37 -0700110
Rich Lane78a3bc42013-11-29 19:22:08 -0800111 def peek(self, fmt, offset=0):
Rich Lane1de06ab2013-04-26 16:58:37 -0700112 st = struct.Struct(fmt)
Rich Lane5df3fd82013-12-01 14:53:06 -0800113 if self.offset + offset + st.size > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700114 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -0800115 result = st.unpack_from(self.buf, self.start + self.offset + offset)
Rich Lane1de06ab2013-04-26 16:58:37 -0700116 return result
117
118 def skip(self, length):
Rich Lane5df3fd82013-12-01 14:53:06 -0800119 if self.offset + length > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700120 raise loxi.ProtocolError("Buffer too short")
121 self.offset += length
122
Rich Laneb564efc2013-07-23 14:19:29 -0700123 def skip_align(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800124 new_offset = ((self.start + self.offset + 7) / 8 * 8) - self.start
125 if new_offset > self.length:
Rich Laneb564efc2013-07-23 14:19:29 -0700126 raise loxi.ProtocolError("Buffer too short")
127 self.offset = new_offset
128
Rich Lane1de06ab2013-04-26 16:58:37 -0700129 def is_empty(self):
Rich Lane5df3fd82013-12-01 14:53:06 -0800130 return self.offset == self.length
Rich Lane1de06ab2013-04-26 16:58:37 -0700131
Rich Lane5df3fd82013-12-01 14:53:06 -0800132 # Used when parsing objects that have their own length fields
Rich Lane1de06ab2013-04-26 16:58:37 -0700133 def slice(self, length):
Rich Lane5df3fd82013-12-01 14:53:06 -0800134 if self.offset + length > self.length:
Rich Lane1de06ab2013-04-26 16:58:37 -0700135 raise loxi.ProtocolError("Buffer too short")
Rich Lane5df3fd82013-12-01 14:53:06 -0800136 reader = OFReader(self.buf, self.start + self.offset, length)
Rich Lane1de06ab2013-04-26 16:58:37 -0700137 self.offset += length
Rich Lane5df3fd82013-12-01 14:53:06 -0800138 return reader