blob: 7f3ac465f53db3a48445f4e837d6ea29696a13e3 [file] [log] [blame]
Nathan Knuth418fdc82016-09-16 22:51:15 -07001# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
2# Copyright (c) 2011, 2012 Open Networking Foundation
3# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
4# See the file LICENSE.pyloxi which should have been included in the source distribution
5"""
6Utility functions independent of the protocol version
7"""
8
9# Automatically generated by LOXI from template generic_util.py
10# Do not modify
11
12import loxi
13import struct
14
15def pack_list(values):
16 return "".join([x.pack() for x in values])
17
18def unpack_list(reader, deserializer):
19 """
20 The deserializer function should take an OFReader and return the new object.
21 """
22 entries = []
23 while not reader.is_empty():
24 entries.append(deserializer(reader))
25 return entries
26
27def pad_to(alignment, length):
28 """
29 Return a string of zero bytes that will pad a string of length 'length' to
30 a multiple of 'alignment'.
31 """
32 return "\x00" * ((length + alignment - 1)/alignment*alignment - length)
33
34class OFReader(object):
35 """
36 Cursor over a read-only buffer
37
38 OpenFlow messages are best thought of as a sequence of elements of
39 variable size, rather than a C-style struct with fixed offsets and
40 known field lengths. This class supports efficiently reading
41 fields sequentially and is intended to be used recursively by the
42 parsers of child objects which will implicitly update the offset.
43
44 buf: buffer object
45 start: initial position in the buffer
46 length: number of bytes after start
47 offset: distance from start
48 """
49 def __init__(self, buf, start=0, length=None):
50 self.buf = buf
51 self.start = start
52 if length is None:
53 self.length = len(buf) - start
54 else:
55 self.length = length
56 self.offset = 0
57
58 def read(self, fmt):
59 st = struct.Struct(fmt)
60 if self.offset + st.size > self.length:
61 raise loxi.ProtocolError("Buffer too short")
62 result = st.unpack_from(self.buf, self.start+self.offset)
63 self.offset += st.size
64 return result
65
66 def read_all(self):
67 s = self.buf[(self.start+self.offset):(self.start+self.length)]
68 assert(len(s) == self.length - self.offset)
69 self.offset = self.length
70 return s
71
72 def peek(self, fmt, offset=0):
73 st = struct.Struct(fmt)
74 if self.offset + offset + st.size > self.length:
75 raise loxi.ProtocolError("Buffer too short")
76 result = st.unpack_from(self.buf, self.start + self.offset + offset)
77 return result
78
79 def skip(self, length):
80 if self.offset + length > self.length:
81 raise loxi.ProtocolError("Buffer too short")
82 self.offset += length
83
84 def skip_align(self):
85 new_offset = (self.offset + 7) / 8 * 8
86 if new_offset > self.length:
87 raise loxi.ProtocolError("Buffer too short")
88 self.offset = new_offset
89
90 def is_empty(self):
91 return self.offset == self.length
92
93 # Used when parsing objects that have their own length fields
94 def slice(self, length, rewind=0):
95 if self.offset + length - rewind > self.length:
96 raise loxi.ProtocolError("Buffer too short")
97 reader = OFReader(self.buf, self.start + self.offset - rewind, length)
98 reader.skip(rewind)
99 self.offset += length - rewind
100 return reader