blob: 1a28e42e4c8b4902d9b66ae145a0b9eb104e57b8 [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 = {
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070041 'byte' : (True, 8, True),
42 'char' : (False, 16, True),
43 'short' : (True, 16, True),
44 'int' : (True, 32, False),
45 'long' : (True, 64, False),
Andreas Wundsam46d230f2013-08-02 22:24:06 -070046}
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 Wundsam22ba3af2013-10-04 16:00:30 -070054 signed, bits, cast_needed = java_primitives_info[t]
Andreas Wundsam46d230f2013-08-02 22:24:06 -070055 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)
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070067 return "%s0x%x%s" % ("(%s) " % t if cast_needed else "", value, "L" if t=="long" else "")
68
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 Wundsam22ba3af2013-10-04 16:00:30 -070073 def __init__(self, version=ANY, read=None, write=None, default=None, funnel=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 Wundsam22ba3af2013-10-04 16:00:30 -070078 self.funnel = funnel
Andreas Wundsame916d6f2013-07-30 11:33:58 -070079
Yotam Harchold7b84202013-07-26 16:08:10 -070080 def __str__(self):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070081 return "[Version: %d, Read: '%s', Write: '%s', Default: '%s', Funnel: '%s' ]" % (self.version, self.read, self.write, self.default, self.funnel )
Yotam Harchold7b84202013-07-26 16:08:10 -070082
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070083### FIXME: This class should really be cleaned up
Andreas Wundsam27303462013-07-16 12:52:35 -070084class JType(object):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070085 """ Wrapper class to hold C to Java type conversion information. JTypes can have a 'public'
86 and or 'private' java type associated with them and can define how those types can be
87 read from and written to ChannelBuffers.
88
89 """
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070090 def __init__(self, pub_type, priv_type=None):
Andreas Wundsam27303462013-07-16 12:52:35 -070091 self.pub_type = pub_type # the type we expose externally, e.g. 'U8'
92 if priv_type is None:
93 priv_type = pub_type
94 self.priv_type = priv_type # the internal storage type
Yotam Harchold7b84202013-07-26 16:08:10 -070095 self.ops = {}
Yotam Harchold7b84202013-07-26 16:08:10 -070096
Andreas Wundsam22ba3af2013-10-04 16:00:30 -070097 def set_priv_type(self, priv_type):
98 self.priv_type = priv_type
99 return self
100
101 def op(self, version=ANY, read=None, write=None, default=None, funnel=None, pub_type=ANY):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700102 """
103 define operations to be performed for reading and writing this type
104 (when read_op, write_op is called). The operations 'read' and 'write'
105 can either be strings ($name, and $version and $length will be replaced),
106 or callables (name, version and length) will be passed.
107
108 @param version int OF version to define operation for, or ANY for all
109 @param pub_type boolean whether to define operations for the public type (True), the
110 private type(False) or both (ALL)
111 @param read read expression (either string or callable)s
112 @param write write expression (either string or callable)
113 """
114
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700115 pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
116 for pub_type in pub_types:
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700117 self.ops[(version, pub_type)] = VersionOp(version, read, write, default, funnel)
Yotam Harchold7b84202013-07-26 16:08:10 -0700118 return self
Andreas Wundsam27303462013-07-16 12:52:35 -0700119
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700120 def format_value(self, value, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700121 # Format a constant value of this type, for inclusion in the java source code
122 # For primitive types, takes care of casting the value appropriately, to
123 # cope with java's signedness limitation
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700124 t = self.pub_type if pub_type else self.priv_type
125 if t in java_primitive_types:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700126 return format_primitive_literal(t, value)
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700127 else:
128 return value
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700129
Andreas Wundsam27303462013-07-16 12:52:35 -0700130 @property
131 def public_type(self):
132 """ return the public type """
133 return self.pub_type
134
135 def priv(self):
136 """ return the public type """
137 return self.priv_type
138
139 def has_priv(self):
140 """ Is the private type different from the public one?"""
141 return self.pub_type != self.priv_type
142
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700143 def get_op(self, op_type, version, pub_type, default_value, arguments):
144 ver = ANY if version is None else version.int_version
145
146 if not "version" in arguments:
147 arguments["version"] = version.of_version
148
149 def lookup(ver, pub_type):
150 if (ver, pub_type) in self.ops:
151 return getattr(self.ops[(ver, pub_type)], op_type)
152 else:
153 return None
154
155 _op = lookup(ver, pub_type) or lookup(ANY, pub_type) or default_value
156 if callable(_op):
157 return _op(**arguments)
158 else:
159 return reduce(lambda a,repl: a.replace("$%s" % repl[0], str(repl[1])), arguments.items(), _op)
160
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700161 def read_op(self, version=None, length=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700162 """ return a Java stanza that reads a value of this JType from ChannelBuffer bb.
163 @param version int - OF wire version to generate expression for
164 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
165 @param length string, for operations that need it (e.g., read a list of unknown length)
166 Java expression evaluating to the byte length to be read. Defaults to the remainig
167 length of the message.
168 @return string containing generated Java expression.
169 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700170 if length is None:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700171 # assumes that
172 # (1) length of the message has been read to 'length'
173 # (2) readerIndex at the start of the message has been stored in 'start'
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700174 length = "length - (bb.readerIndex() - start)"
Andreas Wundsam27303462013-07-16 12:52:35 -0700175
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700176 return self.get_op("read", version, pub_type,
177 default_value='ChannelUtilsVer$version.read%s(bb)' % self.pub_type,
178 arguments=dict(length=length)
179 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700180
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700181 def write_op(self, version=None, name=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700182 """ return a Java stanza that writes a value of this JType contained in Java expression
183 'name' to ChannelBuffer bb.
184 @param name string containing Java expression that evaluations to the value to be written
185 @param version int - OF wire version to generate expression for
186 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
187 @return string containing generated Java expression.
188 """
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700189
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700190 return self.get_op("write", version, pub_type,
191 default_value='ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type,
192 arguments=dict(name=name)
193 )
194
Andreas Wundsam27303462013-07-16 12:52:35 -0700195
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700196 def default_op(self, version=None, pub_type=True):
197 """ return a Java stanza that returns a default value of this JType.
198 @param version JavaOFVersion
199 @return string containing generated Java expression.
200 """
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700201 return self.get_op("default", version, pub_type,
202 arguments = dict(),
203 default_value = self.format_value(0) if self.is_primitive else "null"
204 )
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700205
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 Wundsam22ba3af2013-10-04 16:00:30 -0700213 def funnel_op(self, version=None, name=None, pub_type=True):
214 t = self.pub_type if pub_type else self.priv_type
215 return self.get_op("funnel", version, pub_type,
216 arguments = dict(name=name),
217 default_value = '$name.putTo(sink)' if not self._is_primitive(pub_type) else "sink.put{}($name)".format(t[0].upper() + t[1:])
218 )
219
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700220 @property
221 def is_primitive(self):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700222 return self._is_primitive()
223
224 def _is_primitive(self, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700225 """ return true if the pub_type is a java primitive type (and thus needs
226 special treatment, because it doesn't have methods)"""
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700227 t = self.pub_type if pub_type else self.priv_type
228 return t in java_primitive_types
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700229
230 @property
231 def is_array(self):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700232 return self._is_array()
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700233
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700234 def _is_array(self, pub_type=True):
235 t = self.pub_type if pub_type else self.priv_type
236 return t.endswith("[]")
237
238# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
239def gen_enum_jtype(java_name, is_bitmask=False):
240 if is_bitmask:
241 java_type = "Set<{}>".format(java_name)
242 default_value = "ImmutableSet.<{}>of()".format(java_name)
243 else:
244 java_type = java_name
245 default_value = "null"
246
247 serializer = "{}SerializerVer$version".format(java_name)
248
249 return JType(java_type)\
250 .op(read="{}.readFrom(bb)".format(serializer),
251 write="{}.writeTo(bb, $name)".format(serializer),
252 default=default_value,
253 funnel="{}.putTo($name, sink)".format(serializer)
254 )
255
256def gen_list_jtype(java_base_name):
257 # read op assumes the class has a public final static field READER that implements
258 # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
259 # write op assumes class implements Writeable
260 return JType("List<{}>".format(java_base_name)) \
261 .op(
262 read= 'ChannelUtils.readList(bb, $length, {}Ver$version.READER)'.format(java_base_name), \
263 write='ChannelUtils.writeList(bb, $name)',
264 default="ImmutableList.<{}>of()".format(java_base_name),
265 funnel='FunnelUtils.putList($name, sink)'
266 )
267
268def gen_fixed_length_string_jtype(length):
269 return JType('String').op(
270 read='ChannelUtils.readFixedLengthString(bb, {})'.format(length),
271 write='ChannelUtils.writeFixedLengthString(bb, $name, {})'.format(length),
272 default='""',
273 funnel='sink.putUnencodedChars($name)'
274 )
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700275
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700276##### Predefined JType mappings
277# FIXME: This list needs to be pruned / cleaned up. Most of these are schematic.
278
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700279u8 = JType('short', 'byte') \
Andreas Wundsam83d877a2013-09-30 14:26:44 -0700280 .op(read='U8.f(bb.readByte())', write='bb.writeByte(U8.t($name))', pub_type=True) \
281 .op(read='bb.readByte()', write='bb.writeByte($name)', pub_type=False)
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700282u8_list = JType('List<U8>') \
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700283 .op(read='ChannelUtils.readList(bb, $length, U8.READER)',
284 write='ChannelUtils.writeList(bb, $name)',
285 default='ImmutableList.<U8>of()',
286 funnel='FunnelUtils.putList($name, sink)'
287 )
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700288u16 = JType('int', 'short') \
289 .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))', pub_type=True) \
290 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
291u32 = JType('long', 'int') \
292 .op(read='U32.f(bb.readInt())', write='bb.writeInt(U32.t($name))', pub_type=True) \
293 .op(read='bb.readInt()', write='bb.writeInt($name)', pub_type=False)
294u32_list = JType('List<U32>', 'int[]') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700295 .op(
296 read='ChannelUtils.readList(bb, $length, U32.READER)',
297 write='ChannelUtils.writeList(bb, $name)',
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700298 default="ImmutableList.<U32>of()",
299 funnel="FunnelUtils.putList($name, sink)")
Yotam Harchol5804f772013-08-21 17:35:31 -0700300u8obj = JType('U8', 'U8') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700301 .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
Yotam Harchol5804f772013-08-21 17:35:31 -0700302u32obj = JType('U32', 'U32') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700303 .op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())', default="U32.ZERO")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700304u64 = JType('U64', 'U64') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700305 .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())', default="U64.ZERO")
Yotam Harchold7b84202013-07-26 16:08:10 -0700306of_port = JType("OFPort") \
Andreas Wundsamad499c92013-09-28 18:56:49 -0700307 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ANY") \
308 .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFPort.ANY")
Andreas Wundsame962d372013-10-02 18:15:58 -0700309# the same OFPort, but with a default value of ZERO, only for OF10 match
310of_port_match_v1 = JType("OFPort") \
311 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ZERO")
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700312actions_list = gen_list_jtype("OFAction")
313instructions_list = gen_list_jtype("OFInstruction")
314buckets_list = gen_list_jtype("OFBucket")
315port_desc_list = gen_list_jtype("OFPortDesc")
316packet_queue_list = gen_list_jtype("OFPacketQueue")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700317port_desc = JType('OFPortDesc') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700318 .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700319 write='$name.writeTo(bb)')
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700320octets = JType('byte[]')\
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700321 .op(read='ChannelUtils.readBytes(bb, $length)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700322 write='bb.writeBytes($name)', \
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700323 default="new byte[0]",
324 funnel="sink.putBytes($name)"
325 );
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700326of_match = JType('Match') \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700327 .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
Andreas Wundsame962d372013-10-02 18:15:58 -0700328 write='$name.writeTo(bb)',
329 default="OFFactoryVer$version.MATCH_WILDCARD_ALL");
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700330flow_mod_cmd = JType('OFFlowModCommand', 'short') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700331 .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
332 .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700333mac_addr = JType('MacAddress') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700334 .op(read="MacAddress.read6Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700335 write="$name.write6Bytes(bb)",
336 default="MacAddress.NONE")
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700337
338port_name = gen_fixed_length_string_jtype(16)
339desc_str = gen_fixed_length_string_jtype(256)
340serial_num = gen_fixed_length_string_jtype(32)
341table_name = gen_fixed_length_string_jtype(32)
Yotam Harchola289d552013-09-16 10:10:40 -0700342ipv4 = JType("IPv4Address") \
343 .op(read="IPv4Address.read4Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700344 write="$name.write4Bytes(bb)",
345 default='IPv4Address.NONE')
Yotam Harchola289d552013-09-16 10:10:40 -0700346ipv6 = JType("IPv6Address") \
347 .op(read="IPv6Address.read16Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700348 write="$name.write16Bytes(bb)",
349 default='IPv6Address.NONE')
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700350packetin_reason = gen_enum_jtype("OFPacketInReason")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700351transport_port = JType("TransportPort")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700352 .op(read="TransportPort.read2Bytes(bb)",
353 write="$name.write2Bytes(bb)",
354 default="TransportPort.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700355eth_type = JType("EthType")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700356 .op(read="EthType.read2Bytes(bb)",
357 write="$name.write2Bytes(bb)",
358 default="EthType.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700359vlan_vid = JType("VlanVid")\
Andreas Wundsam55b71ce2013-10-01 19:26:46 -0700360 .op(version=1, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
361 .op(version=2, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
362 .op(version=ANY, read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="VlanVid.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700363vlan_pcp = JType("VlanPcp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700364 .op(read="VlanPcp.readByte(bb)",
365 write="$name.writeByte(bb)",
366 default="VlanPcp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700367ip_dscp = JType("IpDscp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700368 .op(read="IpDscp.readByte(bb)",
369 write="$name.writeByte(bb)",
370 default="IpDscp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700371ip_ecn = JType("IpEcn")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700372 .op(read="IpEcn.readByte(bb)",
373 write="$name.writeByte(bb)",
374 default="IpEcn.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700375ip_proto = JType("IpProtocol")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700376 .op(read="IpProtocol.readByte(bb)",
377 write="$name.writeByte(bb)",
378 default="IpProtocol.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700379icmpv4_type = JType("ICMPv4Type")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700380 .op(read="ICMPv4Type.readByte(bb)",
381 write="$name.writeByte(bb)",
382 default="ICMPv4Type.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700383icmpv4_code = JType("ICMPv4Code")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700384 .op(read="ICMPv4Code.readByte(bb)",
385 write="$name.writeByte(bb)",
386 default="ICMPv4Code.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700387arp_op = JType("ArpOpcode")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700388 .op(read="ArpOpcode.read2Bytes(bb)",
389 write="$name.write2Bytes(bb)",
390 default="ArpOpcode.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700391ipv6_flabel = JType("IPv6FlowLabel")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700392 .op(read="IPv6FlowLabel.read4Bytes(bb)",
393 write="$name.write4Bytes(bb)",
394 default="IPv6FlowLabel.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700395metadata = JType("OFMetadata")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700396 .op(read="OFMetadata.read8Bytes(bb)",
397 write="$name.write8Bytes(bb)",
398 default="OFMetadata.NONE")
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700399oxm = JType("OFOxm<?>")\
400 .op( read="OFOxmVer$version.READER.readFrom(bb)",
401 write="$name.writeTo(bb)")
402oxm_list = JType("OFOxmList") \
403 .op(
404 read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700405 write='$name.writeTo(bb)',
406 default="OFOxmList.EMPTY")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700407meter_features = JType("OFMeterFeatures")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700408 .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
409 write="$name.writeTo(bb)")
410flow_wildcards = JType("int") \
411 .op(read='bb.readInt()',
412 write='bb.writeInt($name)',
413 default="OFFlowWildcardsSerializerVer$version.ALL_VAL")
414table_stats_wildcards = JType("int") \
415 .op(read='bb.readInt()',
416 write='bb.writeInt($name)')
Yotam Harchol2c535582013-10-01 15:50:20 -0700417port_bitmap = JType('OFBitMask128') \
418 .op(read='OFBitMask128.read16Bytes(bb)',
Yotam Harchola11f38b2013-09-26 15:38:17 -0700419 write='$name.write16Bytes(bb)',
Yotam Harchol2c535582013-10-01 15:50:20 -0700420 default='OFBitMask128.NONE')
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700421table_id = JType("TableId") \
422 .op(read='TableId.readByte(bb)',
423 write='$name.writeByte(bb)',
424 default='TableId.ALL')
Andreas Wundsama0981022013-10-02 18:15:06 -0700425of_version = JType("OFVersion", 'byte') \
426 .op(read='bb.readByte()', write='bb.writeByte($name)')
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700427
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700428port_speed = JType("PortSpeed")
Rob Vaterlaus4d311942013-09-24 13:41:44 -0700429error_type = JType("OFErrorType")
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700430boolean = JType("boolean").op(default="false")
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700431of_type = JType("OFType", 'byte') \
432 .op(read='bb.readByte()', write='bb.writeByte($name)')
433action_type= gen_enum_jtype("OFActionType")\
434 .set_priv_type("short")\
435 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
436instruction_type = gen_enum_jtype("OFInstructionType")\
437 .set_priv_type('short') \
438 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
439buffer_id = JType("OFBufferId") \
440 .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700441
442generic_t = JType("T")
443
Andreas Wundsam27303462013-07-16 12:52:35 -0700444
445default_mtype_to_jtype_convert_map = {
446 'uint8_t' : u8,
447 'uint16_t' : u16,
448 'uint32_t' : u32,
449 'uint64_t' : u64,
Andreas Wundsam27303462013-07-16 12:52:35 -0700450 'of_port_no_t' : of_port,
451 'list(of_action_t)' : actions_list,
452 'list(of_instruction_t)' : instructions_list,
453 'list(of_bucket_t)': buckets_list,
454 'list(of_port_desc_t)' : port_desc_list,
455 'list(of_packet_queue_t)' : packet_queue_list,
456 'list(of_uint32_t)' : u32_list,
457 'list(of_uint8_t)' : u8_list,
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700458 'list(of_oxm_t)' : oxm_list,
Andreas Wundsam27303462013-07-16 12:52:35 -0700459 'of_octets_t' : octets,
460 'of_match_t': of_match,
461 'of_fm_cmd_t': flow_mod_cmd,
462 'of_mac_addr_t': mac_addr,
463 'of_port_desc_t': port_desc,
464 'of_desc_str_t': desc_str,
465 'of_serial_num_t': serial_num,
466 'of_port_name_t': port_name,
467 'of_table_name_t': table_name,
468 'of_ipv4_t': ipv4,
469 'of_ipv6_t': ipv6,
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700470 'of_wc_bmap_t': flow_wildcards,
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700471 'of_oxm_t': oxm,
472 'of_meter_features_t': meter_features,
Yotam Harchol595c6442013-09-27 16:29:08 -0700473 'of_bitmap_128_t': port_bitmap
Andreas Wundsam27303462013-07-16 12:52:35 -0700474 }
475
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700476## Map that defines exceptions from the standard loxi->java mapping scheme
477# map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } }
Andreas Wundsam27303462013-07-16 12:52:35 -0700478exceptions = {
Yotam Harcholc742e202013-08-15 12:16:24 -0700479 'of_packet_in': { 'data' : octets, 'reason': packetin_reason },
480 'of_oxm_tcp_src' : { 'value' : transport_port },
481 'of_oxm_tcp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
482 'of_oxm_tcp_dst' : { 'value' : transport_port },
483 'of_oxm_tcp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
484 'of_oxm_udp_src' : { 'value' : transport_port },
485 'of_oxm_udp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
486 'of_oxm_udp_dst' : { 'value' : transport_port },
487 'of_oxm_udp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
488 'of_oxm_sctp_src' : { 'value' : transport_port },
489 'of_oxm_sctp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
490 'of_oxm_sctp_dst' : { 'value' : transport_port },
491 'of_oxm_sctp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
492 'of_oxm_eth_type' : { 'value' : eth_type },
493 'of_oxm_eth_type_masked' : { 'value' : eth_type, 'value_mask' : eth_type },
494 'of_oxm_vlan_vid' : { 'value' : vlan_vid },
495 'of_oxm_vlan_vid_masked' : { 'value' : vlan_vid, 'value_mask' : vlan_vid },
496 'of_oxm_vlan_pcp' : { 'value' : vlan_pcp },
497 'of_oxm_vlan_pcp_masked' : { 'value' : vlan_pcp, 'value_mask' : vlan_pcp },
498 'of_oxm_ip_dscp' : { 'value' : ip_dscp },
499 'of_oxm_ip_dscp_masked' : { 'value' : ip_dscp, 'value_mask' : ip_dscp },
500 'of_oxm_ip_ecn' : { 'value' : ip_ecn },
501 'of_oxm_ip_ecn_masked' : { 'value' : ip_ecn, 'value_mask' : ip_ecn },
502 'of_oxm_ip_proto' : { 'value' : ip_proto },
503 'of_oxm_ip_proto_masked' : { 'value' : ip_proto, 'value_mask' : ip_proto },
504 'of_oxm_icmpv4_type' : { 'value' : icmpv4_type },
505 'of_oxm_icmpv4_type_masked' : { 'value' : icmpv4_type, 'value_mask' : icmpv4_type },
506 'of_oxm_icmpv4_code' : { 'value' : icmpv4_code },
507 'of_oxm_icmpv4_code_masked' : { 'value' : icmpv4_code, 'value_mask' : icmpv4_code },
508 'of_oxm_arp_op' : { 'value' : arp_op },
509 'of_oxm_arp_op_masked' : { 'value' : arp_op, 'value_mask' : arp_op },
510 'of_oxm_arp_spa' : { 'value' : ipv4 },
511 'of_oxm_arp_spa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
512 'of_oxm_arp_tpa' : { 'value' : ipv4 },
513 'of_oxm_arp_tpa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
514 'of_oxm_ipv6_flabel' : { 'value' : ipv6_flabel },
515 'of_oxm_ipv6_flabel_masked' : { 'value' : ipv6_flabel, 'value_mask' : ipv6_flabel },
516 'of_oxm_metadata' : { 'value' : metadata },
517 'of_oxm_metadata_masked' : { 'value' : metadata, 'value_mask' : metadata },
Yotam Harchol5804f772013-08-21 17:35:31 -0700518
519 'of_oxm_icmpv6_code' : { 'value' : u8obj },
520 'of_oxm_icmpv6_code_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
521 'of_oxm_icmpv6_type' : { 'value' : u8obj },
522 'of_oxm_icmpv6_type_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
523 'of_oxm_mpls_label' : { 'value' : u32obj },
524 'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
525 'of_oxm_mpls_tc' : { 'value' : u8obj },
526 'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700527
Yotam Harchol595c6442013-09-27 16:29:08 -0700528 'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
529 'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700530
531 'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
532 'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
533 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
Andreas Wundsame962d372013-10-02 18:15:58 -0700534 'tcp_src': transport_port, 'tcp_dst': transport_port,
535 'in_port': of_port_match_v1
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700536 }
Andreas Wundsam27303462013-07-16 12:52:35 -0700537}
538
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700539
540@memoize
541def enum_java_types():
542 enum_types = {}
543
544 for protocol in of_g.ir.values():
545 for enum in protocol.enums:
546 java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700547
548 enum_types[enum.name] = gen_enum_jtype(java_name, enum.is_bitmask)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700549 return enum_types
550
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700551def make_match_field_jtype(sub_type_name="?"):
552 return JType("MatchField<{}>".format(sub_type_name))
553
Andreas Wundsam27303462013-07-16 12:52:35 -0700554
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700555def list_cname_to_java_name(c_type):
Andreas Wundsam27303462013-07-16 12:52:35 -0700556 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
557 if not m:
558 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
559 base_name = m.group(1)
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700560 return "OF" + name_c_to_caps_camel(base_name)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700561
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700562
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700563#### main entry point for conversion of LOXI types (c_types) Java types.
564# FIXME: This badly needs a refactoring
565
Andreas Wundsam27303462013-07-16 12:52:35 -0700566def convert_to_jtype(obj_name, field_name, c_type):
567 """ Convert from a C type ("uint_32") to a java type ("U32")
568 and return a JType object with the size, internal type, and marshalling functions"""
569 if obj_name in exceptions and field_name in exceptions[obj_name]:
570 return exceptions[obj_name][field_name]
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700571 elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700572 return of_type
Andreas Wundsam27303462013-07-16 12:52:35 -0700573 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700574 return action_type
Andreas Wundsam999c0732013-10-01 19:29:16 -0700575 elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700576 return instruction_type
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700577 elif field_name == "table_id" and c_type == "uint8_t":
578 return table_id
Andreas Wundsam27303462013-07-16 12:52:35 -0700579 elif field_name == "version" and c_type == "uint8_t":
Andreas Wundsama0981022013-10-02 18:15:06 -0700580 return of_version
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700581 elif field_name == "buffer_id" and c_type == "uint32_t":
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700582 return buffer_id
Andreas Wundsam27303462013-07-16 12:52:35 -0700583 elif c_type in default_mtype_to_jtype_convert_map:
584 return default_mtype_to_jtype_convert_map[c_type]
585 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
Andreas Wundsam22ba3af2013-10-04 16:00:30 -0700586 return gen_list_jtype(list_cname_to_java_name(c_type))
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700587 elif c_type in enum_java_types():
588 return enum_java_types()[c_type]
Andreas Wundsam27303462013-07-16 12:52:35 -0700589 else:
590 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
591 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
592 return JType(jtype)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700593
594
595#### Enum specific wiretype definitions
596enum_wire_types = {
597 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
598 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
599 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
600 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
601}
602
603def convert_enum_wire_type_to_jtype(wire_type):
604 return enum_wire_types[wire_type]