blob: 53091ed4c1feef2bc8030e148fdcd0a755ac5d96 [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 Lane1de06ab2013-04-26 16:58:37 -070066class OFReader(object):
67 """
68 Cursor over a read-only buffer
69
70 OpenFlow messages are best thought of as a sequence of elements of
71 variable size, rather than a C-style struct with fixed offsets and
72 known field lengths. This class supports efficiently reading
73 fields sequentially and is intended to be used recursively by the
74 parsers of child objects which will implicitly update the offset.
75 """
76 def __init__(self, buf):
77 self.buf = buf
78 self.offset = 0
79
80 def read(self, fmt):
81 st = struct.Struct(fmt)
82 if self.offset + st.size > len(self.buf):
83 raise loxi.ProtocolError("Buffer too short")
84 result = st.unpack_from(self.buf, self.offset)
85 self.offset += st.size
86 return result
87
88 def read_all(self):
89 buf = buffer(self.buf, self.offset)
90 self.offset += len(buf)
91 return str(buf)
92
93 def peek(self, fmt):
94 st = struct.Struct(fmt)
95 if self.offset + st.size > len(self.buf):
96 raise loxi.ProtocolError("Buffer too short")
97 result = st.unpack_from(self.buf, self.offset)
98 return result
99
100 def skip(self, length):
101 if self.offset + length > len(self.buf):
102 raise loxi.ProtocolError("Buffer too short")
103 self.offset += length
104
105 def is_empty(self):
106 return self.offset == len(self.buf)
107
108 # Used when parsing variable length objects which have external length
109 # fields (e.g. the actions list in an OF 1.0 packet-out message).
110 def slice(self, length):
111 if self.offset + length > len(self.buf):
112 raise loxi.ProtocolError("Buffer too short")
113 buf = OFReader(buffer(self.buf, self.offset, length))
114 self.offset += length
115 return buf