blob: 698d86946598b45fecfcba0892d6bf70f5db1804 [file] [log] [blame]
Yotam Harcholc742e202013-08-15 12:16:24 -07001import errno
Andreas Wundsam27303462013-07-16 12:52:35 -07002import os
Andreas Wundsam27303462013-07-16 12:52:35 -07003import re
4import subprocess
5import time
6
Andreas Wundsam7cfeac32013-09-17 13:53:48 -07007from generic_utils import memoize
8import loxi_utils.loxi_utils as loxi_utils
9import of_g
10
Andreas Wundsam2be7da52013-08-22 07:34:25 -070011def erase_type_annotation(class_name):
12 m=re.match(r'(.*)<.*>', class_name)
13 if m:
14 return m.group(1)
15 else:
16 return class_name
17
Andreas Wundsam27303462013-07-16 12:52:35 -070018def name_c_to_camel(name):
19 """ 'of_stats_reply' -> 'ofStatsReply' """
20 name = re.sub(r'^_','', name)
21 tokens = name.split('_')
22 for i in range(1, len(tokens)):
23 tokens[i] = tokens[i].title()
24 return "".join(tokens)
25
26def name_c_to_caps_camel(name):
27 """ 'of_stats_reply' to 'OFStatsReply' """
28 camel = name_c_to_camel(name.title())
Andreas Wundsam7cfeac32013-09-17 13:53:48 -070029 if camel.startswith('Ofp'):
30 return camel.replace('Ofp','OF',1)
31 elif camel.startswith('Of'):
Andreas Wundsam27303462013-07-16 12:52:35 -070032 return camel.replace('Of','OF',1)
33 else:
34 return camel
35
Andreas Wundsame916d6f2013-07-30 11:33:58 -070036java_primitive_types = set("byte char short int long".split(" "))
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070037
38### info table about java primitive types, for casting literals in the source code
39# { name : (signed?, length_in_bits) }
Andreas Wundsam46d230f2013-08-02 22:24:06 -070040java_primitives_info = {
41 'byte' : (True, 8),
42 'char' : (False, 16),
43 'short' : (True, 16),
44 'int' : (True, 32),
45 'long' : (True, 64),
46}
47
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070048def format_primitive_literal(t, value):
49 """ Format a primitive numeric literal for inclusion in the
50 java source code. Takes care of casting the literal
51 apropriately for correct representation despite Java's
52 signed-craziness
53 """
Andreas Wundsam46d230f2013-08-02 22:24:06 -070054 signed, bits = java_primitives_info[t]
55 max = (1 << bits)-1
56 if value > max:
57 raise Exception("Value %d to large for type %s" % (value, t))
58
59 if signed:
60 max_pos = (1 << (bits-1)) - 1
61
62 if value > max_pos:
63 if t == "long":
64 return str((1 << bits) - value)
65 else:
66 return "(%s) 0x%x" % (t, value)
67 else:
Andreas Wundsam2bf357c2013-08-03 22:50:40 -070068 return "0x%x%s" % (value, "L" if t=="long" else "")
Yotam Harchold7b84202013-07-26 16:08:10 -070069
Andreas Wundsame916d6f2013-07-30 11:33:58 -070070ANY = 0xFFFFFFFFFFFFFFFF
Yotam Harchold7b84202013-07-26 16:08:10 -070071
72class VersionOp:
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070073 def __init__(self, version=ANY, read=None, write=None, default=None):
Yotam Harchold7b84202013-07-26 16:08:10 -070074 self.version = version
75 self.read = read
76 self.write = write
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070077 self.default = default
Andreas Wundsame916d6f2013-07-30 11:33:58 -070078
Yotam Harchold7b84202013-07-26 16:08:10 -070079 def __str__(self):
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070080 return "[Version: %d, Read: '%s', Write: '%s', Default: '%s' ]" % (self.version, self.read, self.write, self.default )
Yotam Harchold7b84202013-07-26 16:08:10 -070081
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070082### FIXME: This class should really be cleaned up
Andreas Wundsam27303462013-07-16 12:52:35 -070083class JType(object):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070084 """ Wrapper class to hold C to Java type conversion information. JTypes can have a 'public'
85 and or 'private' java type associated with them and can define how those types can be
86 read from and written to ChannelBuffers.
87
88 """
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070089 def __init__(self, pub_type, priv_type=None):
Andreas Wundsam27303462013-07-16 12:52:35 -070090 self.pub_type = pub_type # the type we expose externally, e.g. 'U8'
91 if priv_type is None:
92 priv_type = pub_type
93 self.priv_type = priv_type # the internal storage type
Yotam Harchold7b84202013-07-26 16:08:10 -070094 self.ops = {}
Yotam Harchold7b84202013-07-26 16:08:10 -070095
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070096 def op(self, version=ANY, read=None, write=None, default=None, pub_type=ANY):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070097 """
98 define operations to be performed for reading and writing this type
99 (when read_op, write_op is called). The operations 'read' and 'write'
100 can either be strings ($name, and $version and $length will be replaced),
101 or callables (name, version and length) will be passed.
102
103 @param version int OF version to define operation for, or ANY for all
104 @param pub_type boolean whether to define operations for the public type (True), the
105 private type(False) or both (ALL)
106 @param read read expression (either string or callable)s
107 @param write write expression (either string or callable)
108 """
109
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700110 pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
111 for pub_type in pub_types:
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700112 self.ops[(version, pub_type)] = VersionOp(version, read, write, default)
Yotam Harchold7b84202013-07-26 16:08:10 -0700113 return self
Andreas Wundsam27303462013-07-16 12:52:35 -0700114
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700115 def format_value(self, value, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700116 # Format a constant value of this type, for inclusion in the java source code
117 # For primitive types, takes care of casting the value appropriately, to
118 # cope with java's signedness limitation
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700119 t = self.pub_type if pub_type else self.priv_type
120 if t in java_primitive_types:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700121 return format_primitive_literal(t, value)
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700122 else:
123 return value
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700124
Andreas Wundsam27303462013-07-16 12:52:35 -0700125 @property
126 def public_type(self):
127 """ return the public type """
128 return self.pub_type
129
130 def priv(self):
131 """ return the public type """
132 return self.priv_type
133
134 def has_priv(self):
135 """ Is the private type different from the public one?"""
136 return self.pub_type != self.priv_type
137
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700138 def read_op(self, version=None, length=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700139 """ return a Java stanza that reads a value of this JType from ChannelBuffer bb.
140 @param version int - OF wire version to generate expression for
141 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
142 @param length string, for operations that need it (e.g., read a list of unknown length)
143 Java expression evaluating to the byte length to be read. Defaults to the remainig
144 length of the message.
145 @return string containing generated Java expression.
146 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700147 if length is None:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700148 # assumes that
149 # (1) length of the message has been read to 'length'
150 # (2) readerIndex at the start of the message has been stored in 'start'
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700151 length = "length - (bb.readerIndex() - start)";
Andreas Wundsam27303462013-07-16 12:52:35 -0700152
Yotam Harchold7b84202013-07-26 16:08:10 -0700153 ver = ANY if version is None else version.int_version
154 _read_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700155 if (ver, pub_type) in self.ops:
156 _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read
157 elif (ANY, pub_type) in self.ops:
158 _read_op = self.ops[(ANY, pub_type)].read
Yotam Harchold7b84202013-07-26 16:08:10 -0700159 if _read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -0700160 _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700161 if callable(_read_op):
162 return _read_op(version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700163 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700164 return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700165
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700166 def write_op(self, version=None, name=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700167 """ return a Java stanza that writes a value of this JType contained in Java expression
168 'name' to ChannelBuffer bb.
169 @param name string containing Java expression that evaluations to the value to be written
170 @param version int - OF wire version to generate expression for
171 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
172 @return string containing generated Java expression.
173 """
Yotam Harchold7b84202013-07-26 16:08:10 -0700174 ver = ANY if version is None else version.int_version
175 _write_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700176 if (ver, pub_type) in self.ops:
177 _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write
178 elif (ANY, pub_type) in self.ops:
179 _write_op = self.ops[(ANY, pub_type)].write
Yotam Harchold7b84202013-07-26 16:08:10 -0700180 if _write_op is None:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700181
Andreas Wundsam951ada32013-08-01 22:05:38 -0700182 _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700183 if callable(_write_op):
184 return _write_op(version, name)
Andreas Wundsam27303462013-07-16 12:52:35 -0700185 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700186 return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700187
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700188 def default_op(self, version=None, pub_type=True):
189 """ return a Java stanza that returns a default value of this JType.
190 @param version JavaOFVersion
191 @return string containing generated Java expression.
192 """
193 ver = ANY if version is None else version.int_version
194 _default_op = None
195 if (ver, pub_type) in self.ops:
196 _default_op = self.ops[(ver, pub_type)].default or self.ops[(ANY, pub_type)].default
197 elif (ANY, pub_type) in self.ops:
198 _default_op = self.ops[(ANY, pub_type)].default
199 if _default_op is None:
200 _default_op = self.format_value(0) if self.is_primitive else "null"
201 if callable(_default_op):
202 return _default_op(version, name)
203 else:
204 return _default_op.replace("$version", version.of_version)
205
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700206 def skip_op(self, version=None, length=None):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700207 """ return a java stanza that skips an instance of JType in the input ChannelBuffer 'bb'.
208 This is used in the Reader implementations for virtual classes (because after the
209 discriminator field, the concrete Reader instance will re-read all the fields)
210 Currently just delegates to read_op + throws away the result."""
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700211 return self.read_op(version, length)
212
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700213 @property
214 def is_primitive(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700215 """ return true if the pub_type is a java primitive type (and thus needs
216 special treatment, because it doesn't have methods)"""
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700217 return self.pub_type in java_primitive_types
218
219 @property
220 def is_array(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700221 """ return true iff the pub_type is a Java array (and thus requires special
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700222 treatment for equals / toString etc.) """
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700223 return self.pub_type.endswith("[]")
224
225
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700226##### Predefined JType mappings
227# FIXME: This list needs to be pruned / cleaned up. Most of these are schematic.
228
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700229u8 = JType('short', 'byte') \
Andreas Wundsam83d877a2013-09-30 14:26:44 -0700230 .op(read='U8.f(bb.readByte())', write='bb.writeByte(U8.t($name))', pub_type=True) \
231 .op(read='bb.readByte()', write='bb.writeByte($name)', pub_type=False)
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700232u8_list = JType('List<U8>') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700233 .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700234u16 = JType('int', 'short') \
235 .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))', pub_type=True) \
236 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
237u32 = JType('long', 'int') \
238 .op(read='U32.f(bb.readInt())', write='bb.writeInt(U32.t($name))', pub_type=True) \
239 .op(read='bb.readInt()', write='bb.writeInt($name)', pub_type=False)
240u32_list = JType('List<U32>', 'int[]') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700241 .op(
242 read='ChannelUtils.readList(bb, $length, U32.READER)',
243 write='ChannelUtils.writeList(bb, $name)',
244 default="ImmutableList.<U32>of()");
Yotam Harchol5804f772013-08-21 17:35:31 -0700245u8obj = JType('U8', 'U8') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700246 .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
Yotam Harchol5804f772013-08-21 17:35:31 -0700247u32obj = JType('U32', 'U32') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700248 .op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())', default="U32.ZERO")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700249u64 = JType('U64', 'U64') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700250 .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())', default="U64.ZERO")
Yotam Harchold7b84202013-07-26 16:08:10 -0700251of_port = JType("OFPort") \
Andreas Wundsamad499c92013-09-28 18:56:49 -0700252 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ANY") \
253 .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFPort.ANY")
Andreas Wundsame962d372013-10-02 18:15:58 -0700254# the same OFPort, but with a default value of ZERO, only for OF10 match
255of_port_match_v1 = JType("OFPort") \
256 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ZERO")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700257actions_list = JType('List<OFAction>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700258 .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)',
259 write='ChannelUtils.writeList(bb, $name);',
260 default='ImmutableList.<OFAction>of()')
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700261instructions_list = JType('List<OFInstruction>') \
262 .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700263 write='ChannelUtils.writeList(bb, $name)',
264 default='ImmutableList.<OFInstruction>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700265buckets_list = JType('List<OFBucket>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700266 .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)',
267 write='ChannelUtils.writeList(bb, $name)',
268 default='ImmutableList.<OFBucket>of()')
Rob Vaterlaus7db900a2013-09-17 14:18:49 -0700269port_desc_list = JType('List<OFPortDesc>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700270 .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)',
271 write='ChannelUtils.writeList(bb, $name)',
272 default='ImmutableList.<OFPortDesc>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700273port_desc = JType('OFPortDesc') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700274 .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700275 write='$name.writeTo(bb)')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700276packet_queue_list = JType('List<OFPacketQueue>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700277 .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)',
278 write='ChannelUtils.writeList(bb, $name);',
279 default='ImmutableList.<OFPacketQueue>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700280octets = JType('byte[]') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700281 .op(read='ChannelUtils.readBytes(bb, $length)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700282 write='bb.writeBytes($name)', \
283 default="new byte[0]");
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700284of_match = JType('Match') \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700285 .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
Andreas Wundsame962d372013-10-02 18:15:58 -0700286 write='$name.writeTo(bb)',
287 default="OFFactoryVer$version.MATCH_WILDCARD_ALL");
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700288flow_mod_cmd = JType('OFFlowModCommand', 'short') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700289 .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
290 .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700291mac_addr = JType('MacAddress') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700292 .op(read="MacAddress.read6Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700293 write="$name.write6Bytes(bb)",
294 default="MacAddress.NONE")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700295port_name = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700296 .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700297 write='ChannelUtils.writeFixedLengthString(bb, $name, 16)',
298 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700299desc_str = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700300 .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700301 write='ChannelUtils.writeFixedLengthString(bb, $name, 256)',
302 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700303serial_num = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700304 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700305 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
306 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700307table_name = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700308 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700309 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
310 default='""')
Yotam Harchola289d552013-09-16 10:10:40 -0700311ipv4 = JType("IPv4Address") \
312 .op(read="IPv4Address.read4Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700313 write="$name.write4Bytes(bb)",
314 default='IPv4Address.NONE')
Yotam Harchola289d552013-09-16 10:10:40 -0700315ipv6 = JType("IPv6Address") \
316 .op(read="IPv6Address.read16Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700317 write="$name.write16Bytes(bb)",
318 default='IPv6Address.NONE')
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700319packetin_reason = JType("OFPacketInReason")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700320 .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)",
321 write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700322transport_port = JType("TransportPort")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700323 .op(read="TransportPort.read2Bytes(bb)",
324 write="$name.write2Bytes(bb)",
325 default="TransportPort.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700326eth_type = JType("EthType")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700327 .op(read="EthType.read2Bytes(bb)",
328 write="$name.write2Bytes(bb)",
329 default="EthType.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700330vlan_vid = JType("VlanVid")\
Andreas Wundsam55b71ce2013-10-01 19:26:46 -0700331 .op(version=1, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
332 .op(version=2, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
333 .op(version=ANY, read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="VlanVid.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700334vlan_pcp = JType("VlanPcp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700335 .op(read="VlanPcp.readByte(bb)",
336 write="$name.writeByte(bb)",
337 default="VlanPcp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700338ip_dscp = JType("IpDscp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700339 .op(read="IpDscp.readByte(bb)",
340 write="$name.writeByte(bb)",
341 default="IpDscp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700342ip_ecn = JType("IpEcn")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700343 .op(read="IpEcn.readByte(bb)",
344 write="$name.writeByte(bb)",
345 default="IpEcn.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700346ip_proto = JType("IpProtocol")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700347 .op(read="IpProtocol.readByte(bb)",
348 write="$name.writeByte(bb)",
349 default="IpProtocol.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700350icmpv4_type = JType("ICMPv4Type")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700351 .op(read="ICMPv4Type.readByte(bb)",
352 write="$name.writeByte(bb)",
353 default="ICMPv4Type.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700354icmpv4_code = JType("ICMPv4Code")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700355 .op(read="ICMPv4Code.readByte(bb)",
356 write="$name.writeByte(bb)",
357 default="ICMPv4Code.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700358arp_op = JType("ArpOpcode")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700359 .op(read="ArpOpcode.read2Bytes(bb)",
360 write="$name.write2Bytes(bb)",
361 default="ArpOpcode.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700362ipv6_flabel = JType("IPv6FlowLabel")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700363 .op(read="IPv6FlowLabel.read4Bytes(bb)",
364 write="$name.write4Bytes(bb)",
365 default="IPv6FlowLabel.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700366metadata = JType("OFMetadata")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700367 .op(read="OFMetadata.read8Bytes(bb)",
368 write="$name.write8Bytes(bb)",
369 default="OFMetadata.NONE")
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700370oxm = JType("OFOxm<?>")\
371 .op( read="OFOxmVer$version.READER.readFrom(bb)",
372 write="$name.writeTo(bb)")
373oxm_list = JType("OFOxmList") \
374 .op(
375 read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700376 write='$name.writeTo(bb)',
377 default="OFOxmList.EMPTY")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700378meter_features = JType("OFMeterFeatures")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700379 .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
380 write="$name.writeTo(bb)")
381flow_wildcards = JType("int") \
382 .op(read='bb.readInt()',
383 write='bb.writeInt($name)',
384 default="OFFlowWildcardsSerializerVer$version.ALL_VAL")
385table_stats_wildcards = JType("int") \
386 .op(read='bb.readInt()',
387 write='bb.writeInt($name)')
Yotam Harchol2c535582013-10-01 15:50:20 -0700388port_bitmap = JType('OFBitMask128') \
389 .op(read='OFBitMask128.read16Bytes(bb)',
Yotam Harchola11f38b2013-09-26 15:38:17 -0700390 write='$name.write16Bytes(bb)',
Yotam Harchol2c535582013-10-01 15:50:20 -0700391 default='OFBitMask128.NONE')
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700392table_id = JType("TableId") \
393 .op(read='TableId.readByte(bb)',
394 write='$name.writeByte(bb)',
395 default='TableId.ALL')
Andreas Wundsama0981022013-10-02 18:15:06 -0700396of_version = JType("OFVersion", 'byte') \
397 .op(read='bb.readByte()', write='bb.writeByte($name)')
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700398
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700399port_speed = JType("PortSpeed")
Rob Vaterlaus4d311942013-09-24 13:41:44 -0700400error_type = JType("OFErrorType")
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700401boolean = JType("boolean").op(default="false")
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700402
403generic_t = JType("T")
404
Andreas Wundsam27303462013-07-16 12:52:35 -0700405
406default_mtype_to_jtype_convert_map = {
407 'uint8_t' : u8,
408 'uint16_t' : u16,
409 'uint32_t' : u32,
410 'uint64_t' : u64,
Andreas Wundsam27303462013-07-16 12:52:35 -0700411 'of_port_no_t' : of_port,
412 'list(of_action_t)' : actions_list,
413 'list(of_instruction_t)' : instructions_list,
414 'list(of_bucket_t)': buckets_list,
415 'list(of_port_desc_t)' : port_desc_list,
416 'list(of_packet_queue_t)' : packet_queue_list,
417 'list(of_uint32_t)' : u32_list,
418 'list(of_uint8_t)' : u8_list,
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700419 'list(of_oxm_t)' : oxm_list,
Andreas Wundsam27303462013-07-16 12:52:35 -0700420 'of_octets_t' : octets,
421 'of_match_t': of_match,
422 'of_fm_cmd_t': flow_mod_cmd,
423 'of_mac_addr_t': mac_addr,
424 'of_port_desc_t': port_desc,
425 'of_desc_str_t': desc_str,
426 'of_serial_num_t': serial_num,
427 'of_port_name_t': port_name,
428 'of_table_name_t': table_name,
429 'of_ipv4_t': ipv4,
430 'of_ipv6_t': ipv6,
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700431 'of_wc_bmap_t': flow_wildcards,
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700432 'of_oxm_t': oxm,
433 'of_meter_features_t': meter_features,
Yotam Harchol595c6442013-09-27 16:29:08 -0700434 'of_bitmap_128_t': port_bitmap
Andreas Wundsam27303462013-07-16 12:52:35 -0700435 }
436
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700437## Map that defines exceptions from the standard loxi->java mapping scheme
438# map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } }
Andreas Wundsam27303462013-07-16 12:52:35 -0700439exceptions = {
Yotam Harcholc742e202013-08-15 12:16:24 -0700440 'of_packet_in': { 'data' : octets, 'reason': packetin_reason },
441 'of_oxm_tcp_src' : { 'value' : transport_port },
442 'of_oxm_tcp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
443 'of_oxm_tcp_dst' : { 'value' : transport_port },
444 'of_oxm_tcp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
445 'of_oxm_udp_src' : { 'value' : transport_port },
446 'of_oxm_udp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
447 'of_oxm_udp_dst' : { 'value' : transport_port },
448 'of_oxm_udp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
449 'of_oxm_sctp_src' : { 'value' : transport_port },
450 'of_oxm_sctp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
451 'of_oxm_sctp_dst' : { 'value' : transport_port },
452 'of_oxm_sctp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
453 'of_oxm_eth_type' : { 'value' : eth_type },
454 'of_oxm_eth_type_masked' : { 'value' : eth_type, 'value_mask' : eth_type },
455 'of_oxm_vlan_vid' : { 'value' : vlan_vid },
456 'of_oxm_vlan_vid_masked' : { 'value' : vlan_vid, 'value_mask' : vlan_vid },
457 'of_oxm_vlan_pcp' : { 'value' : vlan_pcp },
458 'of_oxm_vlan_pcp_masked' : { 'value' : vlan_pcp, 'value_mask' : vlan_pcp },
459 'of_oxm_ip_dscp' : { 'value' : ip_dscp },
460 'of_oxm_ip_dscp_masked' : { 'value' : ip_dscp, 'value_mask' : ip_dscp },
461 'of_oxm_ip_ecn' : { 'value' : ip_ecn },
462 'of_oxm_ip_ecn_masked' : { 'value' : ip_ecn, 'value_mask' : ip_ecn },
463 'of_oxm_ip_proto' : { 'value' : ip_proto },
464 'of_oxm_ip_proto_masked' : { 'value' : ip_proto, 'value_mask' : ip_proto },
465 'of_oxm_icmpv4_type' : { 'value' : icmpv4_type },
466 'of_oxm_icmpv4_type_masked' : { 'value' : icmpv4_type, 'value_mask' : icmpv4_type },
467 'of_oxm_icmpv4_code' : { 'value' : icmpv4_code },
468 'of_oxm_icmpv4_code_masked' : { 'value' : icmpv4_code, 'value_mask' : icmpv4_code },
469 'of_oxm_arp_op' : { 'value' : arp_op },
470 'of_oxm_arp_op_masked' : { 'value' : arp_op, 'value_mask' : arp_op },
471 'of_oxm_arp_spa' : { 'value' : ipv4 },
472 'of_oxm_arp_spa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
473 'of_oxm_arp_tpa' : { 'value' : ipv4 },
474 'of_oxm_arp_tpa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
475 'of_oxm_ipv6_flabel' : { 'value' : ipv6_flabel },
476 'of_oxm_ipv6_flabel_masked' : { 'value' : ipv6_flabel, 'value_mask' : ipv6_flabel },
477 'of_oxm_metadata' : { 'value' : metadata },
478 'of_oxm_metadata_masked' : { 'value' : metadata, 'value_mask' : metadata },
Yotam Harchol5804f772013-08-21 17:35:31 -0700479
480 'of_oxm_icmpv6_code' : { 'value' : u8obj },
481 'of_oxm_icmpv6_code_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
482 'of_oxm_icmpv6_type' : { 'value' : u8obj },
483 'of_oxm_icmpv6_type_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
484 'of_oxm_mpls_label' : { 'value' : u32obj },
485 'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
486 'of_oxm_mpls_tc' : { 'value' : u8obj },
487 'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
Yotam Harchola11f38b2013-09-26 15:38:17 -0700488
Yotam Harchol595c6442013-09-27 16:29:08 -0700489 'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
490 'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700491
492 'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
493 'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
494 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
Andreas Wundsame962d372013-10-02 18:15:58 -0700495 'tcp_src': transport_port, 'tcp_dst': transport_port,
496 'in_port': of_port_match_v1
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700497 }
Andreas Wundsam27303462013-07-16 12:52:35 -0700498}
499
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700500
501@memoize
502def enum_java_types():
503 enum_types = {}
504
505 for protocol in of_g.ir.values():
506 for enum in protocol.enums:
507 java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700508 if enum.is_bitmask:
509 java_type = "Set<{}>".format(java_name)
510 default_value = "ImmutableSet.<{}>of()".format(java_name)
511 else:
512 java_type = java_name
513 default_value = "null"
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700514 enum_types[enum.name] = \
515 JType(java_type)\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700516 .op(read="{}SerializerVer$version.readFrom(bb)".format(java_name),
517 write="{}SerializerVer$version.writeTo(bb, $name)".format(java_name),
518 default=default_value)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700519 return enum_types
520
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700521def make_match_field_jtype(sub_type_name="?"):
522 return JType("MatchField<{}>".format(sub_type_name))
523
Andreas Wundsam27303462013-07-16 12:52:35 -0700524
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700525# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
Andreas Wundsam27303462013-07-16 12:52:35 -0700526def make_standard_list_jtype(c_type):
527 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
528 if not m:
529 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
530 base_name = m.group(1)
531 java_base_name = name_c_to_caps_camel(base_name)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700532
533 # read op assumes the class has a public final static field READER that implements
534 # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
535 # write op assumes class implements Writeable
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700536 return JType("List<OF{}>".format(java_base_name)) \
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700537 .op(
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700538 read= 'ChannelUtils.readList(bb, $length, OF{}Ver$version.READER)'.format(java_base_name), \
539 write='ChannelUtils.writeList(bb, $name)',
540 default="ImmutableList.<OF{}>of()".format(java_base_name)
541 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700542
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700543
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700544
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700545#### main entry point for conversion of LOXI types (c_types) Java types.
546# FIXME: This badly needs a refactoring
547
Andreas Wundsam27303462013-07-16 12:52:35 -0700548def convert_to_jtype(obj_name, field_name, c_type):
549 """ Convert from a C type ("uint_32") to a java type ("U32")
550 and return a JType object with the size, internal type, and marshalling functions"""
551 if obj_name in exceptions and field_name in exceptions[obj_name]:
552 return exceptions[obj_name][field_name]
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700553 elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t":
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700554 return JType("OFType", 'byte') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700555 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700556 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700557 return JType("OFActionType", 'short') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700558 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
559 .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Andreas Wundsam999c0732013-10-01 19:29:16 -0700560 elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
561 return JType("OFInstructionType", 'short') \
562 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
563 .op(read="OFInstructionTypeSerializerVer$version.readFrom(bb)", write="OFInstructionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700564 elif field_name == "table_id" and c_type == "uint8_t":
565 return table_id
Andreas Wundsam27303462013-07-16 12:52:35 -0700566 elif field_name == "version" and c_type == "uint8_t":
Andreas Wundsama0981022013-10-02 18:15:06 -0700567 return of_version
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700568 elif field_name == "buffer_id" and c_type == "uint32_t":
569 return JType("OFBufferId") \
Rob Vaterlausfbd5b6b2013-09-24 15:55:47 -0700570 .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
Andreas Wundsam27303462013-07-16 12:52:35 -0700571 elif c_type in default_mtype_to_jtype_convert_map:
572 return default_mtype_to_jtype_convert_map[c_type]
573 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
574 return make_standard_list_jtype(c_type)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700575 elif c_type in enum_java_types():
576 return enum_java_types()[c_type]
Andreas Wundsam27303462013-07-16 12:52:35 -0700577 else:
578 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
579 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
580 return JType(jtype)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700581
582
583#### Enum specific wiretype definitions
584enum_wire_types = {
585 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
586 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
587 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
588 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
589}
590
591def convert_enum_wire_type_to_jtype(wire_type):
592 return enum_wire_types[wire_type]