blob: 02db1a625808f3e5a80ff5d76b053809f6f80e64 [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 Wundsam45c95f82013-10-08 15:04:23 -0700397table_id_default_zero = JType("TableId") \
398 .op(read='TableId.readByte(bb)',
399 write='$name.writeByte(bb)',
400 default='TableId.ZERO')
Andreas Wundsama0981022013-10-02 18:15:06 -0700401of_version = JType("OFVersion", 'byte') \
402 .op(read='bb.readByte()', write='bb.writeByte($name)')
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700403
Andreas Wundsam8ec3bcc2013-09-16 19:44:00 -0700404port_speed = JType("PortSpeed")
Rob Vaterlaus4d311942013-09-24 13:41:44 -0700405error_type = JType("OFErrorType")
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700406boolean = JType("boolean", "byte") \
407 .op(read='(bb.readByte() != 0)',
408 write='bb.writeByte($name ? 1 : 0)',
409 default="false")
410datapath_id = JType("DatapathId") \
411 .op(read='DatapathId.of(bb.readLong())',
412 write='bb.writeLong($name.getLong())',
413 default='DatapathId.NONE')
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700414
415generic_t = JType("T")
416
Andreas Wundsam27303462013-07-16 12:52:35 -0700417
418default_mtype_to_jtype_convert_map = {
419 'uint8_t' : u8,
420 'uint16_t' : u16,
421 'uint32_t' : u32,
422 'uint64_t' : u64,
Andreas Wundsam27303462013-07-16 12:52:35 -0700423 'of_port_no_t' : of_port,
424 'list(of_action_t)' : actions_list,
425 'list(of_instruction_t)' : instructions_list,
426 'list(of_bucket_t)': buckets_list,
427 'list(of_port_desc_t)' : port_desc_list,
428 'list(of_packet_queue_t)' : packet_queue_list,
429 'list(of_uint32_t)' : u32_list,
430 'list(of_uint8_t)' : u8_list,
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700431 'list(of_oxm_t)' : oxm_list,
Andreas Wundsam27303462013-07-16 12:52:35 -0700432 'of_octets_t' : octets,
433 'of_match_t': of_match,
434 'of_fm_cmd_t': flow_mod_cmd,
435 'of_mac_addr_t': mac_addr,
436 'of_port_desc_t': port_desc,
437 'of_desc_str_t': desc_str,
438 'of_serial_num_t': serial_num,
439 'of_port_name_t': port_name,
440 'of_table_name_t': table_name,
441 'of_ipv4_t': ipv4,
442 'of_ipv6_t': ipv6,
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700443 'of_wc_bmap_t': flow_wildcards,
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700444 'of_oxm_t': oxm,
445 'of_meter_features_t': meter_features,
Yotam Harchol595c6442013-09-27 16:29:08 -0700446 'of_bitmap_128_t': port_bitmap
Andreas Wundsam27303462013-07-16 12:52:35 -0700447 }
448
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700449## Map that defines exceptions from the standard loxi->java mapping scheme
450# map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } }
Andreas Wundsam27303462013-07-16 12:52:35 -0700451exceptions = {
Yotam Harcholc742e202013-08-15 12:16:24 -0700452 'of_packet_in': { 'data' : octets, 'reason': packetin_reason },
453 'of_oxm_tcp_src' : { 'value' : transport_port },
454 'of_oxm_tcp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
455 'of_oxm_tcp_dst' : { 'value' : transport_port },
456 'of_oxm_tcp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
457 'of_oxm_udp_src' : { 'value' : transport_port },
458 'of_oxm_udp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
459 'of_oxm_udp_dst' : { 'value' : transport_port },
460 'of_oxm_udp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
461 'of_oxm_sctp_src' : { 'value' : transport_port },
462 'of_oxm_sctp_src_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
463 'of_oxm_sctp_dst' : { 'value' : transport_port },
464 'of_oxm_sctp_dst_masked' : { 'value' : transport_port, 'value_mask' : transport_port },
465 'of_oxm_eth_type' : { 'value' : eth_type },
466 'of_oxm_eth_type_masked' : { 'value' : eth_type, 'value_mask' : eth_type },
467 'of_oxm_vlan_vid' : { 'value' : vlan_vid },
468 'of_oxm_vlan_vid_masked' : { 'value' : vlan_vid, 'value_mask' : vlan_vid },
469 'of_oxm_vlan_pcp' : { 'value' : vlan_pcp },
470 'of_oxm_vlan_pcp_masked' : { 'value' : vlan_pcp, 'value_mask' : vlan_pcp },
471 'of_oxm_ip_dscp' : { 'value' : ip_dscp },
472 'of_oxm_ip_dscp_masked' : { 'value' : ip_dscp, 'value_mask' : ip_dscp },
473 'of_oxm_ip_ecn' : { 'value' : ip_ecn },
474 'of_oxm_ip_ecn_masked' : { 'value' : ip_ecn, 'value_mask' : ip_ecn },
475 'of_oxm_ip_proto' : { 'value' : ip_proto },
476 'of_oxm_ip_proto_masked' : { 'value' : ip_proto, 'value_mask' : ip_proto },
477 'of_oxm_icmpv4_type' : { 'value' : icmpv4_type },
478 'of_oxm_icmpv4_type_masked' : { 'value' : icmpv4_type, 'value_mask' : icmpv4_type },
479 'of_oxm_icmpv4_code' : { 'value' : icmpv4_code },
480 'of_oxm_icmpv4_code_masked' : { 'value' : icmpv4_code, 'value_mask' : icmpv4_code },
481 'of_oxm_arp_op' : { 'value' : arp_op },
482 'of_oxm_arp_op_masked' : { 'value' : arp_op, 'value_mask' : arp_op },
483 'of_oxm_arp_spa' : { 'value' : ipv4 },
484 'of_oxm_arp_spa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
485 'of_oxm_arp_tpa' : { 'value' : ipv4 },
486 'of_oxm_arp_tpa_masked' : { 'value' : ipv4, 'value_mask' : ipv4 },
487 'of_oxm_ipv6_flabel' : { 'value' : ipv6_flabel },
488 'of_oxm_ipv6_flabel_masked' : { 'value' : ipv6_flabel, 'value_mask' : ipv6_flabel },
489 'of_oxm_metadata' : { 'value' : metadata },
490 'of_oxm_metadata_masked' : { 'value' : metadata, 'value_mask' : metadata },
Yotam Harchol5804f772013-08-21 17:35:31 -0700491
492 'of_oxm_icmpv6_code' : { 'value' : u8obj },
493 'of_oxm_icmpv6_code_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
494 'of_oxm_icmpv6_type' : { 'value' : u8obj },
495 'of_oxm_icmpv6_type_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
496 'of_oxm_mpls_label' : { 'value' : u32obj },
497 'of_oxm_mpls_label_masked' : { 'value' : u32obj, 'value_mask' : u32obj },
498 'of_oxm_mpls_tc' : { 'value' : u8obj },
499 'of_oxm_mpls_tc_masked' : { 'value' : u8obj, 'value_mask' : u8obj },
Yotam Harchola11f38b2013-09-26 15:38:17 -0700500
Yotam Harchol595c6442013-09-27 16:29:08 -0700501 'of_oxm_bsn_in_ports_128' : { 'value': port_bitmap },
502 'of_oxm_bsn_in_ports_128_masked' : { 'value': port_bitmap, 'value_mask': port_bitmap },
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700503
504 'of_table_stats_entry': { 'wildcards': table_stats_wildcards },
505 'of_match_v1': { 'vlan_vid' : vlan_vid, 'vlan_pcp': vlan_pcp,
506 'eth_type': eth_type, 'ip_dscp': ip_dscp, 'ip_proto': ip_proto,
Andreas Wundsame962d372013-10-02 18:15:58 -0700507 'tcp_src': transport_port, 'tcp_dst': transport_port,
508 'in_port': of_port_match_v1
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700509 },
510 'of_bsn_set_l2_table_request': { 'l2_table_enable': boolean },
511 'of_bsn_set_l2_table_reply': { 'l2_table_enable': boolean },
Rob Vaterlause1b86842013-10-18 13:29:19 -0700512 'of_bsn_set_pktin_suppression_request': { 'enabled': boolean },
Andreas Wundsam27303462013-07-16 12:52:35 -0700513}
514
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700515
516@memoize
517def enum_java_types():
518 enum_types = {}
519
520 for protocol in of_g.ir.values():
521 for enum in protocol.enums:
522 java_name = name_c_to_caps_camel(re.sub(r'_t$', "", enum.name))
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700523 if enum.is_bitmask:
524 java_type = "Set<{}>".format(java_name)
525 default_value = "ImmutableSet.<{}>of()".format(java_name)
526 else:
527 java_type = java_name
528 default_value = "null"
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700529 enum_types[enum.name] = \
530 JType(java_type)\
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700531 .op(read="{}SerializerVer$version.readFrom(bb)".format(java_name),
532 write="{}SerializerVer$version.writeTo(bb, $name)".format(java_name),
533 default=default_value)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700534 return enum_types
535
Andreas Wundsam2be7da52013-08-22 07:34:25 -0700536def make_match_field_jtype(sub_type_name="?"):
537 return JType("MatchField<{}>".format(sub_type_name))
538
Andreas Wundsam27303462013-07-16 12:52:35 -0700539
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700540# Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}>
Andreas Wundsam27303462013-07-16 12:52:35 -0700541def make_standard_list_jtype(c_type):
542 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
543 if not m:
544 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
545 base_name = m.group(1)
546 java_base_name = name_c_to_caps_camel(base_name)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700547
548 # read op assumes the class has a public final static field READER that implements
549 # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer
550 # write op assumes class implements Writeable
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700551 return JType("List<OF{}>".format(java_base_name)) \
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700552 .op(
Andreas Wundsamb3ed3ff2013-09-23 14:46:29 -0700553 read= 'ChannelUtils.readList(bb, $length, OF{}Ver$version.READER)'.format(java_base_name), \
554 write='ChannelUtils.writeList(bb, $name)',
555 default="ImmutableList.<OF{}>of()".format(java_base_name)
556 )
Andreas Wundsam27303462013-07-16 12:52:35 -0700557
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700558
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700559
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700560#### main entry point for conversion of LOXI types (c_types) Java types.
561# FIXME: This badly needs a refactoring
562
Andreas Wundsam27303462013-07-16 12:52:35 -0700563def convert_to_jtype(obj_name, field_name, c_type):
564 """ Convert from a C type ("uint_32") to a java type ("U32")
565 and return a JType object with the size, internal type, and marshalling functions"""
566 if obj_name in exceptions and field_name in exceptions[obj_name]:
567 return exceptions[obj_name][field_name]
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700568 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 -0700569 return JType("OFType", 'byte') \
Yotam Harchold7b84202013-07-26 16:08:10 -0700570 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700571 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Andreas Wundsam2bf357c2013-08-03 22:50:40 -0700572 return JType("OFActionType", 'short') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700573 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
574 .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700575 elif field_name == "err_type":
576 return JType("OFErrorType", 'short') \
577 .op(read='bb.readShort()', write='bb.writeShort($name)')
578 elif field_name == "stats_type":
579 return JType("OFStatsType", 'short') \
580 .op(read='bb.readShort()', write='bb.writeShort($name)')
Andreas Wundsam999c0732013-10-01 19:29:16 -0700581 elif field_name == "type" and re.match(r'of_instruction.*', obj_name):
582 return JType("OFInstructionType", 'short') \
583 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
584 .op(read="OFInstructionTypeSerializerVer$version.readFrom(bb)", write="OFInstructionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Andreas Wundsam45c95f82013-10-08 15:04:23 -0700585 elif obj_name in ("of_flow_add", "of_flow_modify", "of_flow_modify_strict", "of_delete_strict") and field_name == "table_id" and c_type == "uint8_t":
586 return table_id_default_zero
Andreas Wundsam37e0fb12013-09-28 18:57:57 -0700587 elif field_name == "table_id" and c_type == "uint8_t":
588 return table_id
Andreas Wundsam27303462013-07-16 12:52:35 -0700589 elif field_name == "version" and c_type == "uint8_t":
Andreas Wundsama0981022013-10-02 18:15:06 -0700590 return of_version
Rob Vaterlausb10ae552013-09-23 14:39:39 -0700591 elif field_name == "buffer_id" and c_type == "uint32_t":
592 return JType("OFBufferId") \
Rob Vaterlausfbd5b6b2013-09-24 15:55:47 -0700593 .op(read="OFBufferId.of(bb.readInt())", write="bb.writeInt($name.getInt())", default="OFBufferId.NO_BUFFER")
Rob Vaterlausfeee3712013-09-30 11:24:19 -0700594 elif field_name == 'datapath_id':
595 return datapath_id
596 elif field_name == 'actions' and obj_name == 'of_features_reply':
597 return JType("Set<OFActionType>") \
598 .op(read='ChannelUtilsVer10.readSupportedActions(bb)',
599 write='ChannelUtilsVer10.writeSupportedActions(bb, $name)',
600 default='ImmutableSet.<OFActionType>of()')
Andreas Wundsam27303462013-07-16 12:52:35 -0700601 elif c_type in default_mtype_to_jtype_convert_map:
602 return default_mtype_to_jtype_convert_map[c_type]
603 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
604 return make_standard_list_jtype(c_type)
Andreas Wundsam7cfeac32013-09-17 13:53:48 -0700605 elif c_type in enum_java_types():
606 return enum_java_types()[c_type]
Andreas Wundsam27303462013-07-16 12:52:35 -0700607 else:
608 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
609 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
610 return JType(jtype)
Andreas Wundsamd8bcedf2013-08-03 21:23:37 -0700611
612
613#### Enum specific wiretype definitions
614enum_wire_types = {
615 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
616 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
617 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
618 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
619}
620
621def convert_enum_wire_type_to_jtype(wire_type):
622 return enum_wire_types[wire_type]