blob: 7f3ac465f53db3a48445f4e837d6ea29696a13e3 [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
Rich Lane7dcdf022013-12-11 14:45:27 -080015def pack_list(values):
16 return "".join([x.pack() for x in values])
17
Rich Laneca3da272013-05-05 09:07:33 -070018def 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
Rich Laned53156a2013-08-05 17:17:33 -070027def 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
Rich Laneca3da272013-05-05 09:07:33 -070034class 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.
Rich Lane7dcdf022013-12-11 14:45:27 -080043
44 buf: buffer object
45 start: initial position in the buffer
46 length: number of bytes after start
47 offset: distance from start
Rich Laneca3da272013-05-05 09:07:33 -070048 """
Rich Lane7dcdf022013-12-11 14:45:27 -080049 def __init__(self, buf, start=0, length=None):
Rich Laneca3da272013-05-05 09:07:33 -070050 self.buf = buf
Rich Lane7dcdf022013-12-11 14:45:27 -080051 self.start = start
52 if length is None:
53 self.length = len(buf) - start
54 else:
55 self.length = length
Rich Laneca3da272013-05-05 09:07:33 -070056 self.offset = 0
57
58 def read(self, fmt):
59 st = struct.Struct(fmt)
Rich Lane7dcdf022013-12-11 14:45:27 -080060 if self.offset + st.size > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070061 raise loxi.ProtocolError("Buffer too short")
Rich Lane7dcdf022013-12-11 14:45:27 -080062 result = st.unpack_from(self.buf, self.start+self.offset)
Rich Laneca3da272013-05-05 09:07:33 -070063 self.offset += st.size
64 return result
65
66 def read_all(self):
Rich Lane7dcdf022013-12-11 14:45:27 -080067 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
Rich Laneca3da272013-05-05 09:07:33 -070071
Rich Lane7dcdf022013-12-11 14:45:27 -080072 def peek(self, fmt, offset=0):
Rich Laneca3da272013-05-05 09:07:33 -070073 st = struct.Struct(fmt)
Rich Lane7dcdf022013-12-11 14:45:27 -080074 if self.offset + offset + st.size > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070075 raise loxi.ProtocolError("Buffer too short")
Rich Lane7dcdf022013-12-11 14:45:27 -080076 result = st.unpack_from(self.buf, self.start + self.offset + offset)
Rich Laneca3da272013-05-05 09:07:33 -070077 return result
78
79 def skip(self, length):
Rich Lane7dcdf022013-12-11 14:45:27 -080080 if self.offset + length > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070081 raise loxi.ProtocolError("Buffer too short")
82 self.offset += length
83
Rich Laned53156a2013-08-05 17:17:33 -070084 def skip_align(self):
Rich Lanecb18dbd2014-12-18 10:02:29 -080085 new_offset = (self.offset + 7) / 8 * 8
Rich Lane7dcdf022013-12-11 14:45:27 -080086 if new_offset > self.length:
Rich Laned53156a2013-08-05 17:17:33 -070087 raise loxi.ProtocolError("Buffer too short")
88 self.offset = new_offset
89
Rich Laneca3da272013-05-05 09:07:33 -070090 def is_empty(self):
Rich Lane7dcdf022013-12-11 14:45:27 -080091 return self.offset == self.length
Rich Laneca3da272013-05-05 09:07:33 -070092
Rich Lane7dcdf022013-12-11 14:45:27 -080093 # Used when parsing objects that have their own length fields
Rich Lanecb18dbd2014-12-18 10:02:29 -080094 def slice(self, length, rewind=0):
95 if self.offset + length - rewind > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070096 raise loxi.ProtocolError("Buffer too short")
Rich Lanecb18dbd2014-12-18 10:02:29 -080097 reader = OFReader(self.buf, self.start + self.offset - rewind, length)
98 reader.skip(rewind)
99 self.offset += length - rewind
Rich Lane7dcdf022013-12-11 14:45:27 -0800100 return reader