blob: f965e64e7e05eca417014b78fd57051b24f8d74b [file] [log] [blame]
Rich Laneca3da272013-05-05 09:07:33 -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.
Dan Talaycof6202252013-07-02 01:00:29 -07004# See the file LICENSE.pyloxi which should have been included in the source distribution
Rich Laneca3da272013-05-05 09:07:33 -07005"""
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 unpack_list(reader, deserializer):
16 """
17 The deserializer function should take an OFReader and return the new object.
18 """
19 entries = []
20 while not reader.is_empty():
21 entries.append(deserializer(reader))
22 return entries
23
24def unpack_list_lv16(reader, deserializer):
25 """
26 The deserializer function should take an OFReader and return the new object.
27 """
28 def wrapper(reader):
29 length, = reader.peek('!H')
30 return deserializer(reader.slice(length))
31 return unpack_list(reader, wrapper)
32
33def unpack_list_tlv16(reader, deserializer):
34 """
35 The deserializer function should take an OFReader and an integer type
36 and return the new object.
37 """
38 def wrapper(reader):
39 typ, length, = reader.peek('!HH')
40 return deserializer(reader.slice(length), typ)
41 return unpack_list(reader, wrapper)
42
Rich Laned53156a2013-08-05 17:17:33 -070043def pad_to(alignment, length):
44 """
45 Return a string of zero bytes that will pad a string of length 'length' to
46 a multiple of 'alignment'.
47 """
48 return "\x00" * ((length + alignment - 1)/alignment*alignment - length)
49
Rich Laneca3da272013-05-05 09:07:33 -070050class OFReader(object):
51 """
52 Cursor over a read-only buffer
53
54 OpenFlow messages are best thought of as a sequence of elements of
55 variable size, rather than a C-style struct with fixed offsets and
56 known field lengths. This class supports efficiently reading
57 fields sequentially and is intended to be used recursively by the
58 parsers of child objects which will implicitly update the offset.
59 """
60 def __init__(self, buf):
61 self.buf = buf
62 self.offset = 0
63
64 def read(self, fmt):
65 st = struct.Struct(fmt)
66 if self.offset + st.size > len(self.buf):
67 raise loxi.ProtocolError("Buffer too short")
68 result = st.unpack_from(self.buf, self.offset)
69 self.offset += st.size
70 return result
71
72 def read_all(self):
73 buf = buffer(self.buf, self.offset)
74 self.offset += len(buf)
75 return str(buf)
76
77 def peek(self, fmt):
78 st = struct.Struct(fmt)
79 if self.offset + st.size > len(self.buf):
80 raise loxi.ProtocolError("Buffer too short")
81 result = st.unpack_from(self.buf, self.offset)
82 return result
83
84 def skip(self, length):
85 if self.offset + length > len(self.buf):
86 raise loxi.ProtocolError("Buffer too short")
87 self.offset += length
88
Rich Laned53156a2013-08-05 17:17:33 -070089 def skip_align(self):
90 new_offset = (self.offset + 7) / 8 * 8
91 if new_offset > len(self.buf):
92 raise loxi.ProtocolError("Buffer too short")
93 self.offset = new_offset
94
Rich Laneca3da272013-05-05 09:07:33 -070095 def is_empty(self):
96 return self.offset == len(self.buf)
97
98 # Used when parsing variable length objects which have external length
99 # fields (e.g. the actions list in an OF 1.0 packet-out message).
100 def slice(self, length):
101 if self.offset + length > len(self.buf):
102 raise loxi.ProtocolError("Buffer too short")
103 buf = OFReader(buffer(self.buf, self.offset, length))
104 self.offset += length
105 return buf