blob: 90aa672224d846fbf739166cfe0665ddfef2a1ad [file] [log] [blame]
Matteo Scandoloa229eca2017-08-08 13:05:28 -07001
2# Copyright 2017-present Open Networking Foundation
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16
Rich Laneca3da272013-05-05 09:07:33 -070017# Copyright (c) 2008 The Board of Trustees of The Leland Stanford Junior University
18# Copyright (c) 2011, 2012 Open Networking Foundation
19# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
Dan Talaycof6202252013-07-02 01:00:29 -070020# See the file LICENSE.pyloxi which should have been included in the source distribution
Rich Laneca3da272013-05-05 09:07:33 -070021"""
22Utility functions independent of the protocol version
23"""
24
25# Automatically generated by LOXI from template generic_util.py
26# Do not modify
27
28import loxi
29import struct
30
Rich Lane7dcdf022013-12-11 14:45:27 -080031def pack_list(values):
32 return "".join([x.pack() for x in values])
33
Rich Laneca3da272013-05-05 09:07:33 -070034def unpack_list(reader, deserializer):
35 """
36 The deserializer function should take an OFReader and return the new object.
37 """
38 entries = []
39 while not reader.is_empty():
40 entries.append(deserializer(reader))
41 return entries
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.
Rich Lane7dcdf022013-12-11 14:45:27 -080059
60 buf: buffer object
61 start: initial position in the buffer
62 length: number of bytes after start
63 offset: distance from start
Rich Laneca3da272013-05-05 09:07:33 -070064 """
Rich Lane7dcdf022013-12-11 14:45:27 -080065 def __init__(self, buf, start=0, length=None):
Rich Laneca3da272013-05-05 09:07:33 -070066 self.buf = buf
Rich Lane7dcdf022013-12-11 14:45:27 -080067 self.start = start
68 if length is None:
69 self.length = len(buf) - start
70 else:
71 self.length = length
Rich Laneca3da272013-05-05 09:07:33 -070072 self.offset = 0
73
74 def read(self, fmt):
75 st = struct.Struct(fmt)
Rich Lane7dcdf022013-12-11 14:45:27 -080076 if self.offset + st.size > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070077 raise loxi.ProtocolError("Buffer too short")
Rich Lane7dcdf022013-12-11 14:45:27 -080078 result = st.unpack_from(self.buf, self.start+self.offset)
Rich Laneca3da272013-05-05 09:07:33 -070079 self.offset += st.size
80 return result
81
82 def read_all(self):
Rich Lane7dcdf022013-12-11 14:45:27 -080083 s = self.buf[(self.start+self.offset):(self.start+self.length)]
84 assert(len(s) == self.length - self.offset)
85 self.offset = self.length
86 return s
Rich Laneca3da272013-05-05 09:07:33 -070087
Rich Lane7dcdf022013-12-11 14:45:27 -080088 def peek(self, fmt, offset=0):
Rich Laneca3da272013-05-05 09:07:33 -070089 st = struct.Struct(fmt)
Rich Lane7dcdf022013-12-11 14:45:27 -080090 if self.offset + offset + st.size > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070091 raise loxi.ProtocolError("Buffer too short")
Rich Lane7dcdf022013-12-11 14:45:27 -080092 result = st.unpack_from(self.buf, self.start + self.offset + offset)
Rich Laneca3da272013-05-05 09:07:33 -070093 return result
94
95 def skip(self, length):
Rich Lane7dcdf022013-12-11 14:45:27 -080096 if self.offset + length > self.length:
Rich Laneca3da272013-05-05 09:07:33 -070097 raise loxi.ProtocolError("Buffer too short")
98 self.offset += length
99
Rich Laned53156a2013-08-05 17:17:33 -0700100 def skip_align(self):
Rich Lanecb18dbd2014-12-18 10:02:29 -0800101 new_offset = (self.offset + 7) / 8 * 8
Rich Lane7dcdf022013-12-11 14:45:27 -0800102 if new_offset > self.length:
Rich Laned53156a2013-08-05 17:17:33 -0700103 raise loxi.ProtocolError("Buffer too short")
104 self.offset = new_offset
105
Rich Laneca3da272013-05-05 09:07:33 -0700106 def is_empty(self):
Rich Lane7dcdf022013-12-11 14:45:27 -0800107 return self.offset == self.length
Rich Laneca3da272013-05-05 09:07:33 -0700108
Rich Lane7dcdf022013-12-11 14:45:27 -0800109 # Used when parsing objects that have their own length fields
Rich Lanecb18dbd2014-12-18 10:02:29 -0800110 def slice(self, length, rewind=0):
111 if self.offset + length - rewind > self.length:
Rich Laneca3da272013-05-05 09:07:33 -0700112 raise loxi.ProtocolError("Buffer too short")
Rich Lanecb18dbd2014-12-18 10:02:29 -0800113 reader = OFReader(self.buf, self.start + self.offset - rewind, length)
114 reader.skip(rewind)
115 self.offset += length - rewind
Rich Lane7dcdf022013-12-11 14:45:27 -0800116 return reader