blob: 169b3f0996d5909f16c995b457c4d0a0fc93fdfa [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
Rob Vaterlausfeee3712013-09-30 11:24:19 -070036java_primitive_types = set("boolean 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 = {
Rob Vaterlausfeee3712013-09-30 11:24:19 -070041 'boolean' : (False, 8),
Andreas Wundsam46d230f2013-08-02 22:24:06 -070042 'byte' : (True, 8),
43 'char' : (False, 16),
44 'short' : (True, 16),
45 'int' : (True, 32),
46 'long' : (True, 64),
47}
48
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070049def format_primitive_literal(t, value):
50 """ Format a primitive numeric literal for inclusion in the
51 java source code. Takes care of casting the literal
Rob Vaterlausfeee3712013-09-30 11:24:19 -070052 appropriately for correct representation despite Java's
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070053 signed-craziness
54 """
Andreas Wundsam46d230f2013-08-02 22:24:06 -070055 signed, bits = java_primitives_info[t]
56 max = (1 << bits)-1
57 if value > max:
58 raise Exception("Value %d to large for type %s" % (value, t))
59
60 if signed:
61 max_pos = (1 << (bits-1)) - 1
62
63 if value > max_pos:
64 if t == "long":
65 return str((1 << bits) - value)
66 else:
67 return "(%s) 0x%x" % (t, value)
68 else:
Andreas Wundsam2bf357c2013-08-03 22:50:40 -070069 return "0x%x%s" % (value, "L" if t=="long" else "")
Yotam Harchold7b84202013-07-26 16:08:10 -070070
Andreas Wundsame916d6f2013-07-30 11:33:58 -070071ANY = 0xFFFFFFFFFFFFFFFF
Yotam Harchold7b84202013-07-26 16:08:10 -070072
73class VersionOp:
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070074 def __init__(self, version=ANY, read=None, write=None, default=None):
Yotam Harchold7b84202013-07-26 16:08:10 -070075 self.version = version
76 self.read = read
77 self.write = write
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070078 self.default = default
Andreas Wundsame916d6f2013-07-30 11:33:58 -070079
Yotam Harchold7b84202013-07-26 16:08:10 -070080 def __str__(self):
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -070081 return "[Version: %d, Read: '%s', Write: '%s', Default: '%s' ]" % (self.version, self.read, self.write, self.default )
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 Wundsamb3ed3ff2013-09-23 14:46:29 -070097 def op(self, version=ANY, read=None, write=None, default=None, pub_type=ANY):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -070098 """
99 define operations to be performed for reading and writing this type
100 (when read_op, write_op is called). The operations 'read' and 'write'
101 can either be strings ($name, and $version and $length will be replaced),
102 or callables (name, version and length) will be passed.
103
104 @param version int OF version to define operation for, or ANY for all
105 @param pub_type boolean whether to define operations for the public type (True), the
106 private type(False) or both (ALL)
107 @param read read expression (either string or callable)s
108 @param write write expression (either string or callable)
109 """
110
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700111 pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
112 for pub_type in pub_types:
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700113 self.ops[(version, pub_type)] = VersionOp(version, read, write, default)
Yotam Harchold7b84202013-07-26 16:08:10 -0700114 return self
Andreas Wundsam27303462013-07-16 12:52:35 -0700115
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700116 def format_value(self, value, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700117 # Format a constant value of this type, for inclusion in the java source code
118 # For primitive types, takes care of casting the value appropriately, to
119 # cope with java's signedness limitation
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700120 t = self.pub_type if pub_type else self.priv_type
121 if t in java_primitive_types:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700122 return format_primitive_literal(t, value)
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700123 else:
124 return value
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700125
Andreas Wundsam27303462013-07-16 12:52:35 -0700126 @property
127 def public_type(self):
128 """ return the public type """
129 return self.pub_type
130
131 def priv(self):
132 """ return the public type """
133 return self.priv_type
134
135 def has_priv(self):
136 """ Is the private type different from the public one?"""
137 return self.pub_type != self.priv_type
138
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700139 def read_op(self, version=None, length=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700140 """ return a Java stanza that reads a value of this JType from ChannelBuffer bb.
141 @param version int - OF wire version to generate expression for
142 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
143 @param length string, for operations that need it (e.g., read a list of unknown length)
144 Java expression evaluating to the byte length to be read. Defaults to the remainig
145 length of the message.
146 @return string containing generated Java expression.
147 """
Andreas Wundsam27303462013-07-16 12:52:35 -0700148 if length is None:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700149 # assumes that
150 # (1) length of the message has been read to 'length'
151 # (2) readerIndex at the start of the message has been stored in 'start'
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700152 length = "length - (bb.readerIndex() - start)";
Andreas Wundsam27303462013-07-16 12:52:35 -0700153
Yotam Harchold7b84202013-07-26 16:08:10 -0700154 ver = ANY if version is None else version.int_version
155 _read_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700156 if (ver, pub_type) in self.ops:
157 _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read
158 elif (ANY, pub_type) in self.ops:
159 _read_op = self.ops[(ANY, pub_type)].read
Yotam Harchold7b84202013-07-26 16:08:10 -0700160 if _read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -0700161 _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700162 if callable(_read_op):
163 return _read_op(version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700164 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700165 return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700166
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700167 def write_op(self, version=None, name=None, pub_type=True):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700168 """ return a Java stanza that writes a value of this JType contained in Java expression
169 'name' to ChannelBuffer bb.
170 @param name string containing Java expression that evaluations to the value to be written
171 @param version int - OF wire version to generate expression for
172 @param pub_type boolean use this JTypes 'public' (True), or private (False) representation
173 @return string containing generated Java expression.
174 """
Yotam Harchold7b84202013-07-26 16:08:10 -0700175 ver = ANY if version is None else version.int_version
176 _write_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700177 if (ver, pub_type) in self.ops:
178 _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write
179 elif (ANY, pub_type) in self.ops:
180 _write_op = self.ops[(ANY, pub_type)].write
Yotam Harchold7b84202013-07-26 16:08:10 -0700181 if _write_op is None:
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700182
Andreas Wundsam951ada32013-08-01 22:05:38 -0700183 _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700184 if callable(_write_op):
185 return _write_op(version, name)
Andreas Wundsam27303462013-07-16 12:52:35 -0700186 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700187 return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700188
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700189 def default_op(self, version=None, pub_type=True):
190 """ return a Java stanza that returns a default value of this JType.
191 @param version JavaOFVersion
192 @return string containing generated Java expression.
193 """
194 ver = ANY if version is None else version.int_version
195 _default_op = None
196 if (ver, pub_type) in self.ops:
197 _default_op = self.ops[(ver, pub_type)].default or self.ops[(ANY, pub_type)].default
198 elif (ANY, pub_type) in self.ops:
199 _default_op = self.ops[(ANY, pub_type)].default
200 if _default_op is None:
201 _default_op = self.format_value(0) if self.is_primitive else "null"
202 if callable(_default_op):
203 return _default_op(version, name)
204 else:
205 return _default_op.replace("$version", version.of_version)
206
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700207 def skip_op(self, version=None, length=None):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700208 """ return a java stanza that skips an instance of JType in the input ChannelBuffer 'bb'.
209 This is used in the Reader implementations for virtual classes (because after the
210 discriminator field, the concrete Reader instance will re-read all the fields)
211 Currently just delegates to read_op + throws away the result."""
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700212 return self.read_op(version, length)
213
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700214 @property
215 def is_primitive(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700216 """ return true if the pub_type is a java primitive type (and thus needs
217 special treatment, because it doesn't have methods)"""
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700218 return self.pub_type in java_primitive_types
219
220 @property
221 def is_array(self):
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700222 """ return true iff the pub_type is a Java array (and thus requires special
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700223 treatment for equals / toString etc.) """
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700224 return self.pub_type.endswith("[]")
225
226
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700227##### Predefined JType mappings
228# FIXME: This list needs to be pruned / cleaned up. Most of these are schematic.
229
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700230u8 = JType('short', 'byte') \
Andreas Wundsam83d877a2013-09-30 14:26:44 -0700231 .op(read='U8.f(bb.readByte())', write='bb.writeByte(U8.t($name))', pub_type=True) \
232 .op(read='bb.readByte()', write='bb.writeByte($name)', pub_type=False)
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700233u8_list = JType('List<U8>') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700234 .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700235u16 = JType('int', 'short') \
236 .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))', pub_type=True) \
237 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)
238u32 = JType('long', 'int') \
239 .op(read='U32.f(bb.readInt())', write='bb.writeInt(U32.t($name))', pub_type=True) \
240 .op(read='bb.readInt()', write='bb.writeInt($name)', pub_type=False)
241u32_list = JType('List<U32>', 'int[]') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700242 .op(
243 read='ChannelUtils.readList(bb, $length, U32.READER)',
244 write='ChannelUtils.writeList(bb, $name)',
245 default="ImmutableList.<U32>of()");
Yotam Harchol5804f772013-08-21 17:35:31 -0700246u8obj = JType('U8', 'U8') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700247 .op(read='U8.of(bb.readByte())', write='bb.writeByte($name.getRaw())', default="U8.ZERO")
Yotam Harchol5804f772013-08-21 17:35:31 -0700248u32obj = JType('U32', 'U32') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700249 .op(read='U32.of(bb.readInt())', write='bb.writeInt($name.getRaw())', default="U32.ZERO")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700250u64 = JType('U64', 'U64') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700251 .op(read='U64.ofRaw(bb.readLong())', write='bb.writeLong($name.getValue())', default="U64.ZERO")
Yotam Harchold7b84202013-07-26 16:08:10 -0700252of_port = JType("OFPort") \
Andreas Wundsamad499c92013-09-28 18:56:49 -0700253 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ANY") \
254 .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)", default="OFPort.ANY")
Andreas Wundsame962d372013-10-02 18:15:58 -0700255# the same OFPort, but with a default value of ZERO, only for OF10 match
256of_port_match_v1 = JType("OFPort") \
257 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="OFPort.ZERO")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700258actions_list = JType('List<OFAction>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700259 .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)',
260 write='ChannelUtils.writeList(bb, $name);',
261 default='ImmutableList.<OFAction>of()')
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700262instructions_list = JType('List<OFInstruction>') \
263 .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700264 write='ChannelUtils.writeList(bb, $name)',
265 default='ImmutableList.<OFInstruction>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700266buckets_list = JType('List<OFBucket>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700267 .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)',
268 write='ChannelUtils.writeList(bb, $name)',
269 default='ImmutableList.<OFBucket>of()')
Rob Vaterlaus7db900a2013-09-17 14:18:49 -0700270port_desc_list = JType('List<OFPortDesc>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700271 .op(read='ChannelUtils.readList(bb, $length, OFPortDescVer$version.READER)',
272 write='ChannelUtils.writeList(bb, $name)',
273 default='ImmutableList.<OFPortDesc>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700274port_desc = JType('OFPortDesc') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700275 .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700276 write='$name.writeTo(bb)')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700277packet_queue_list = JType('List<OFPacketQueue>') \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700278 .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)',
279 write='ChannelUtils.writeList(bb, $name);',
280 default='ImmutableList.<OFPacketQueue>of()')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700281octets = JType('byte[]') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700282 .op(read='ChannelUtils.readBytes(bb, $length)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700283 write='bb.writeBytes($name)', \
284 default="new byte[0]");
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700285of_match = JType('Match') \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700286 .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
Andreas Wundsame962d372013-10-02 18:15:58 -0700287 write='$name.writeTo(bb)',
288 default="OFFactoryVer$version.MATCH_WILDCARD_ALL");
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700289flow_mod_cmd = JType('OFFlowModCommand', 'short') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700290 .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
291 .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700292mac_addr = JType('MacAddress') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700293 .op(read="MacAddress.read6Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700294 write="$name.write6Bytes(bb)",
295 default="MacAddress.NONE")
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700296port_name = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700297 .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700298 write='ChannelUtils.writeFixedLengthString(bb, $name, 16)',
299 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700300desc_str = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700301 .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700302 write='ChannelUtils.writeFixedLengthString(bb, $name, 256)',
303 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700304serial_num = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700305 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700306 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
307 default='""')
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700308table_name = JType('String') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700309 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700310 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)',
311 default='""')
Yotam Harchola289d552013-09-16 10:10:40 -0700312ipv4 = JType("IPv4Address") \
313 .op(read="IPv4Address.read4Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700314 write="$name.write4Bytes(bb)",
315 default='IPv4Address.NONE')
Yotam Harchola289d552013-09-16 10:10:40 -0700316ipv6 = JType("IPv6Address") \
317 .op(read="IPv6Address.read16Bytes(bb)", \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700318 write="$name.write16Bytes(bb)",
319 default='IPv6Address.NONE')
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700320packetin_reason = JType("OFPacketInReason")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700321 .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)",
322 write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700323transport_port = JType("TransportPort")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700324 .op(read="TransportPort.read2Bytes(bb)",
325 write="$name.write2Bytes(bb)",
326 default="TransportPort.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700327eth_type = JType("EthType")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700328 .op(read="EthType.read2Bytes(bb)",
329 write="$name.write2Bytes(bb)",
330 default="EthType.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700331vlan_vid = JType("VlanVid")\
Andreas Wundsam55b71ce2013-10-01 19:26:46 -0700332 .op(version=1, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
333 .op(version=2, read="VlanVid.read2BytesOF10(bb)", write="$name.write2BytesOF10(bb)", default="VlanVid.NONE") \
334 .op(version=ANY, read="VlanVid.read2Bytes(bb)", write="$name.write2Bytes(bb)", default="VlanVid.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700335vlan_pcp = JType("VlanPcp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700336 .op(read="VlanPcp.readByte(bb)",
337 write="$name.writeByte(bb)",
338 default="VlanPcp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700339ip_dscp = JType("IpDscp")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700340 .op(read="IpDscp.readByte(bb)",
341 write="$name.writeByte(bb)",
342 default="IpDscp.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700343ip_ecn = JType("IpEcn")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700344 .op(read="IpEcn.readByte(bb)",
345 write="$name.writeByte(bb)",
346 default="IpEcn.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700347ip_proto = JType("IpProtocol")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700348 .op(read="IpProtocol.readByte(bb)",
349 write="$name.writeByte(bb)",
350 default="IpProtocol.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700351icmpv4_type = JType("ICMPv4Type")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700352 .op(read="ICMPv4Type.readByte(bb)",
353 write="$name.writeByte(bb)",
354 default="ICMPv4Type.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700355icmpv4_code = JType("ICMPv4Code")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700356 .op(read="ICMPv4Code.readByte(bb)",
357 write="$name.writeByte(bb)",
358 default="ICMPv4Code.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700359arp_op = JType("ArpOpcode")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700360 .op(read="ArpOpcode.read2Bytes(bb)",
361 write="$name.write2Bytes(bb)",
362 default="ArpOpcode.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700363ipv6_flabel = JType("IPv6FlowLabel")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700364 .op(read="IPv6FlowLabel.read4Bytes(bb)",
365 write="$name.write4Bytes(bb)",
366 default="IPv6FlowLabel.NONE")
Yotam Harcholc742e202013-08-15 12:16:24 -0700367metadata = JType("OFMetadata")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700368 .op(read="OFMetadata.read8Bytes(bb)",
369 write="$name.write8Bytes(bb)",
370 default="OFMetadata.NONE")
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700371oxm = JType("OFOxm<?>")\
372 .op( read="OFOxmVer$version.READER.readFrom(bb)",
373 write="$name.writeTo(bb)")
374oxm_list = JType("OFOxmList") \
375 .op(
376 read= 'OFOxmList.readFrom(bb, $length, OFOxmVer$version.READER)', \
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700377 write='$name.writeTo(bb)',
378 default="OFOxmList.EMPTY")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700379meter_features = JType("OFMeterFeatures")\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700380 .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)",
381 write="$name.writeTo(bb)")
382flow_wildcards = JType("int") \
383 .op(read='bb.readInt()',
384 write='bb.writeInt($name)',
385 default="OFFlowWildcardsSerializerVer$version.ALL_VAL")
386table_stats_wildcards = JType("int") \
387 .op(read='bb.readInt()',
388 write='bb.writeInt($name)')
Yotam Harchol2c535582013-10-01 15:50:20 -0700389port_bitmap = JType('OFBitMask128') \
390 .op(read='OFBitMask128.read16Bytes(bb)',
Yotam Harchola11f38b2013-09-26 15:38:17 -0700391 write='$name.write16Bytes(bb)',
Yotam Harchol2c535582013-10-01 15:50:20 -0700392 default='OFBitMask128.NONE')
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700393table_id = JType("TableId") \
394 .op(read='TableId.readByte(bb)',
395 write='$name.writeByte(bb)',
396 default='TableId.ALL')
Andreas Wundsama0981022013-10-02 18:15:06 -0700397of_version = JType("OFVersion", 'byte') \
398 .op(read='bb.readByte()', write='bb.writeByte($name)')
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700399
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700400port_speed = JType("PortSpeed")
Rob Vaterlaus4d311942013-09-24 13:41:44 -0700401error_type = JType("OFErrorType")
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700402boolean = JType("boolean", "byte") \
403 .op(read='(bb.readByte() != 0)',
404 write='bb.writeByte($name ? 1 : 0)',
405 default="false")
406datapath_id = JType("DatapathId") \
407 .op(read='DatapathId.of(bb.readLong())',
408 write='bb.writeLong($name.getLong())',
409 default='DatapathId.NONE')
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700410
411generic_t = JType("T")
412
Andreas Wundsam27303462013-07-16 12:52:35 -0700413
414default_mtype_to_jtype_convert_map = {
415 'uint8_t' : u8,
416 'uint16_t' : u16,
417 'uint32_t' : u32,
418 'uint64_t' : u64,
Andreas Wundsam27303462013-07-16 12:52:35 -0700419 'of_port_no_t' : of_port,
420 'list(of_action_t)' : actions_list,
421 'list(of_instruction_t)' : instructions_list,
422 'list(of_bucket_t)': buckets_list,
423 'list(of_port_desc_t)' : port_desc_list,
424 'list(of_packet_queue_t)' : packet_queue_list,
425 'list(of_uint32_t)' : u32_list,
426 'list(of_uint8_t)' : u8_list,
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700427 'list(of_oxm_t)' : oxm_list,
Andreas Wundsam27303462013-07-16 12:52:35 -0700428 'of_octets_t' : octets,
429 'of_match_t': of_match,
430 'of_fm_cmd_t': flow_mod_cmd,
431 'of_mac_addr_t': mac_addr,
432 'of_port_desc_t': port_desc,
433 'of_desc_str_t': desc_str,
434 'of_serial_num_t': serial_num,
435 'of_port_name_t': port_name,
436 'of_table_name_t': table_name,
437 'of_ipv4_t': ipv4,
438 'of_ipv6_t': ipv6,
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700439 'of_wc_bmap_t': flow_wildcards,
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700440 'of_oxm_t': oxm,
441 'of_meter_features_t': meter_features,
Yotam Harchol595c6442013-09-27 16:29:08 -0700442 'of_bitmap_128_t': port_bitmap
Andreas Wundsam27303462013-07-16 12:52:35 -0700443 }
444
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700445## Map that defines exceptions from the standard loxi->java mapping scheme
446# map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } }
Andreas Wundsam27303462013-07-16 12:52:35 -0700447exceptions = {
Yotam Harcholc742e202013-08-15 12:16:24 -0700448 'of_packet_in': { 'data' : octets, 'reason': packetin_reason },
449 'of_oxm_tcp_src' : { 'value' : transport_port },
450 'of_oxm_tcp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
451 'of_oxm_tcp_dst' : { 'value' : transport_port },
452 'of_oxm_tcp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
453 'of_oxm_udp_src' : { 'value' : transport_port },
454 'of_oxm_udp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
455 'of_oxm_udp_dst' : { 'value' : transport_port },
456 'of_oxm_udp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
457 'of_oxm_sctp_src' : { 'value' : transport_port },
458 'of_oxm_sctp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
459 'of_oxm_sctp_dst' : { 'value' : transport_port },
460 'of_oxm_sctp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
461 'of_oxm_eth_type' : { 'value' : eth_type },
462 'of_oxm_eth_type_masked' : { 'value' : eth_type, 'value_mask' : eth_type },
463 'of_oxm_vlan_vid' : { 'value' : vlan_vid },
464 'of_oxm_vlan_vid_masked' : { 'value' : vlan_vid, 'value_mask' : vlan_vid },
465 'of_oxm_vlan_pcp' : { 'value' : vlan_pcp },
466 'of_oxm_vlan_pcp_masked' : { 'value' : vlan_pcp, 'value_mask' : vlan_pcp },
467 'of_oxm_ip_dscp' : { 'value' : ip_dscp },
468 'of_oxm_ip_dscp_masked' : { 'value' : ip_dscp, 'value_mask' : ip_dscp },
469 'of_oxm_ip_ecn' : { 'value' : ip_ecn },
470 'of_oxm_ip_ecn_masked' : { 'value' : ip_ecn, 'value_mask' : ip_ecn },
471 'of_oxm_ip_proto' : { 'value' : ip_proto },
472 'of_oxm_ip_proto_masked' : { 'value' : ip_proto, 'value_mask' : ip_proto },
473 'of_oxm_icmpv4_type' : { 'value' : icmpv4_type },
474 'of_oxm_icmpv4_type_masked' : { 'value' : icmpv4_type, 'value_mask' : icmpv4_type },
475 'of_oxm_icmpv4_code' : { 'value' : icmpv4_code },
476 'of_oxm_icmpv4_code_masked' : { 'value' : icmpv4_code, 'value_mask' : icmpv4_code },
477 'of_oxm_arp_op' : { 'value' : arp_op },
478 'of_oxm_arp_op_masked' : { 'value' : arp_op, 'value_mask' : arp_op },
479 'of_oxm_arp_spa' : { 'value' : ipv4 },
480 'of_oxm_arp_spa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
481 'of_oxm_arp_tpa' : { 'value' : ipv4 },
482 'of_oxm_arp_tpa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
483 'of_oxm_ipv6_flabel' : { 'value' : ipv6_flabel },
484 'of_oxm_ipv6_flabel_masked' : { 'value' : ipv6_flabel, 'value_mask' : ipv6_flabel },
485 'of_oxm_metadata' : { 'value' : metadata },
486 'of_oxm_metadata_masked' : { 'value' : metadata, 'value_mask' : metadata },
Yotam Harchol5804f772013-08-21 17:35:31 -0700487
488 'of_oxm_icmpv6_code' : { 'value' : u8obj },
489 'of_oxm_icmpv6_code_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
490 'of_oxm_icmpv6_type' : { 'value' : u8obj },
491 'of_oxm_icmpv6_type_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
492 'of_oxm_mpls_label' : { 'value' : u32obj },
493 'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
494 'of_oxm_mpls_tc' : { 'value' : u8obj },
495 'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
Yotam Harchola11f38b2013-09-26 15:38:17 -0700496
Yotam Harchol595c6442013-09-27 16:29:08 -0700497 'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
498 'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700499
500 'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
501 'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
502 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
Andreas Wundsame962d372013-10-02 18:15:58 -0700503 'tcp_src': transport_port, 'tcp_dst': transport_port,
504 'in_port': of_port_match_v1
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700505 },
506 'of_bsn_set_l2_table_request': { 'l2_table_enable': boolean },
507 'of_bsn_set_l2_table_reply': { 'l2_table_enable': boolean },
Andreas Wundsam27303462013-07-16 12:52:35 -0700508}
509
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700510
511@memoize
512def enum_java_types():
513 enum_types = {}
514
515 for protocol in of_g.ir.values():
516 for enum in protocol.enums:
517 java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700518 if enum.is_bitmask:
519 java_type = "Set<{}>".format(java_name)
520 default_value = "ImmutableSet.<{}>of()".format(java_name)
521 else:
522 java_type = java_name
523 default_value = "null"
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700524 enum_types[enum.name] = \
525 JType(java_type)\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700526 .op(read="{}SerializerVer$version.readFrom(bb)".format(java_name),
527 write="{}SerializerVer$version.writeTo(bb, $name)".format(java_name),
528 default=default_value)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700529 return enum_types
530
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700531def make_match_field_jtype(sub_type_name="?"):
532 return JType("MatchField<{}>".format(sub_type_name))
533
Andreas Wundsam27303462013-07-16 12:52:35 -0700534
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700535# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
Andreas Wundsam27303462013-07-16 12:52:35 -0700536def make_standard_list_jtype(c_type):
537 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
538 if not m:
539 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
540 base_name = m.group(1)
541 java_base_name = name_c_to_caps_camel(base_name)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700542
543 # read op assumes the class has a public final static field READER that implements
544 # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
545 # write op assumes class implements Writeable
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700546 return JType("List<OF{}>".format(java_base_name)) \
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700547 .op(
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700548 read= 'ChannelUtils.readList(bb, $length, OF{}Ver$version.READER)'.format(java_base_name), \
549 write='ChannelUtils.writeList(bb, $name)',
550 default="ImmutableList.<OF{}>of()".format(java_base_name)
551 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700552
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700553
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700554
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700555#### main entry point for conversion of LOXI types (c_types) Java types.
556# FIXME: This badly needs a refactoring
557
Andreas Wundsam27303462013-07-16 12:52:35 -0700558def convert_to_jtype(obj_name, field_name, c_type):
559 """ Convert from a C type ("uint_32") to a java type ("U32")
560 and return a JType object with the size, internal type, and marshalling functions"""
561 if obj_name in exceptions and field_name in exceptions[obj_name]:
562 return exceptions[obj_name][field_name]
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700563 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 -0700564 return JType("OFType", 'byte') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700565 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700566 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700567 return JType("OFActionType", 'short') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700568 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
569 .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700570 elif field_name == "err_type":
571 return JType("OFErrorType", 'short') \
572 .op(read='bb.readShort()', write='bb.writeShort($name)')
573 elif field_name == "stats_type":
574 return JType("OFStatsType", 'short') \
575 .op(read='bb.readShort()', write='bb.writeShort($name)')
Andreas Wundsam999c0732013-10-01 19:29:16 -0700576 elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
577 return JType("OFInstructionType", 'short') \
578 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
579 .op(read="OFInstructionTypeSerializerVer$version.readFrom(bb)", write="OFInstructionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700580 elif field_name == "table_id" and c_type == "uint8_t":
581 return table_id
Andreas Wundsam27303462013-07-16 12:52:35 -0700582 elif field_name == "version" and c_type == "uint8_t":
Andreas Wundsama0981022013-10-02 18:15:06 -0700583 return of_version
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700584 elif field_name == "buffer_id" and c_type == "uint32_t":
585 return JType("OFBufferId") \
Rob Vaterlausfbd5b6b2013-09-24 15:55:47 -0700586 .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700587 elif field_name == 'datapath_id':
588 return datapath_id
589 elif field_name == 'actions' and obj_name == 'of_features_reply':
590 return JType("Set<OFActionType>") \
591 .op(read='ChannelUtilsVer10.readSupportedActions(bb)',
592 write='ChannelUtilsVer10.writeSupportedActions(bb, $name)',
593 default='ImmutableSet.<OFActionType>of()')
Andreas Wundsam27303462013-07-16 12:52:35 -0700594 elif c_type in default_mtype_to_jtype_convert_map:
595 return default_mtype_to_jtype_convert_map[c_type]
596 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
597 return make_standard_list_jtype(c_type)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700598 elif c_type in enum_java_types():
599 return enum_java_types()[c_type]
Andreas Wundsam27303462013-07-16 12:52:35 -0700600 else:
601 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
602 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
603 return JType(jtype)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700604
605
606#### Enum specific wiretype definitions
607enum_wire_types = {
608 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
609 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
610 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
611 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
612}
613
614def convert_enum_wire_type_to_jtype(wire_type):
615 return enum_wire_types[wire_type]