blob: 28d3b5f3cd2957efe925bf820f34daa49db17f02 [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.
82 """
83 def __init__(self, buf):
84 self.buf = buf
85 self.offset = 0
86
87 def read(self, fmt):
88 st = struct.Struct(fmt)
89 if self.offset + st.size > len(self.buf):
90 raise loxi.ProtocolError("Buffer too short")
91 result = st.unpack_from(self.buf, self.offset)
92 self.offset += st.size
93 return result
94
95 def read_all(self):
96 buf = buffer(self.buf, self.offset)
97 self.offset += len(buf)
98 return str(buf)
99
100 def peek(self, fmt):
101 st = struct.Struct(fmt)
102 if self.offset + st.size > len(self.buf):
103 raise loxi.ProtocolError("Buffer too short")
104 result = st.unpack_from(self.buf, self.offset)
105 return result
106
107 def skip(self, length):
108 if self.offset + length > len(self.buf):
109 raise loxi.ProtocolError("Buffer too short")
110 self.offset += length
111
Rich Laneb564efc2013-07-23 14:19:29 -0700112 def skip_align(self):
113 new_offset = (self.offset + 7) / 8 * 8
114 if new_offset > len(self.buf):
115 raise loxi.ProtocolError("Buffer too short")
116 self.offset = new_offset
117
Rich Lane1de06ab2013-04-26 16:58:37 -0700118 def is_empty(self):
119 return self.offset == len(self.buf)
120
121 # Used when parsing variable length objects which have external length
122 # fields (e.g. the actions list in an OF 1.0 packet-out message).
123 def slice(self, length):
124 if self.offset + length > len(self.buf):
125 raise loxi.ProtocolError("Buffer too short")
126 buf = OFReader(buffer(self.buf, self.offset, length))
127 self.offset += length
128 return buf