blob: 75bde017222e76bf48a11dea099d8b24b31e403b [file] [log] [blame]
Andreas Wundsam27303462013-07-16 12:52:35 -07001import os
2import errno
3import re
4import subprocess
5import time
6
7def name_c_to_camel(name):
8 """ 'of_stats_reply' -> 'ofStatsReply' """
9 name = re.sub(r'^_','', name)
10 tokens = name.split('_')
11 for i in range(1, len(tokens)):
12 tokens[i] = tokens[i].title()
13 return "".join(tokens)
14
15def name_c_to_caps_camel(name):
16 """ 'of_stats_reply' to 'OFStatsReply' """
17 camel = name_c_to_camel(name.title())
18 if camel.startswith('Of'):
19 return camel.replace('Of','OF',1)
20 else:
21 return camel
22
23
Andreas Wundsame916d6f2013-07-30 11:33:58 -070024java_primitive_types = set("byte char short int long".split(" "))
Yotam Harchold7b84202013-07-26 16:08:10 -070025
Andreas Wundsame916d6f2013-07-30 11:33:58 -070026ANY = 0xFFFFFFFFFFFFFFFF
Yotam Harchold7b84202013-07-26 16:08:10 -070027
28class VersionOp:
29 def __init__(self, version=ANY, read=None, write=None):
30 self.version = version
31 self.read = read
32 self.write = write
Andreas Wundsame916d6f2013-07-30 11:33:58 -070033
Yotam Harchold7b84202013-07-26 16:08:10 -070034 def __str__(self):
35 return "[Version: %d, Read: '%s', Write: '%s']" % (self.version, self.read, self.write)
36
Andreas Wundsam27303462013-07-16 12:52:35 -070037class JType(object):
38 """ Wrapper class to hold C to Java type conversion information """
39 def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None):
40 self.pub_type = pub_type # the type we expose externally, e.g. 'U8'
41 if priv_type is None:
42 priv_type = pub_type
43 self.priv_type = priv_type # the internal storage type
44 self.size = size # bytes on the wire; None == variable length or hard to calc
Yotam Harchold7b84202013-07-26 16:08:10 -070045 self.ops = {}
46# if read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -070047# read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -070048# if write_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -070049# write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -070050# self._read_op = read_op
51# self._write_op = write_op
52
53 def op(self, version=ANY, read=None, write=None):
54 self.ops[version] = VersionOp(version, read, write)
55 return self
Andreas Wundsam27303462013-07-16 12:52:35 -070056
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070057 def cast(self, min):
58 """ declares that the value has to be cast to itself for values >= min.
59 This is to deal with Java signedness """
60 def format_cast_value(value):
61 if value >= min:
62 return "(%s) 0x%x" % (self.pub_type, value)
63 else:
64 return "0x%x" % (value)
65
66 self.format_value = format_cast_value
67 return self
68
69 def format_value(self, value):
70 return value
71
Andreas Wundsam27303462013-07-16 12:52:35 -070072 @property
73 def public_type(self):
74 """ return the public type """
75 return self.pub_type
76
77 def priv(self):
78 """ return the public type """
79 return self.priv_type
80
81 def has_priv(self):
82 """ Is the private type different from the public one?"""
83 return self.pub_type != self.priv_type
84
85 def read_op(self, version=None, length=None):
86 if length is None:
87 length = "length - bb.readerIndex()";
88
Yotam Harchold7b84202013-07-26 16:08:10 -070089 ver = ANY if version is None else version.int_version
90 _read_op = None
91 if ver in self.ops:
Andreas Wundsam951ada32013-08-01 22:05:38 -070092 _read_op = self.ops[ver].read or self.ops[ANY].read
Yotam Harchold7b84202013-07-26 16:08:10 -070093 elif ANY in self.ops:
94 _read_op = self.ops[ANY].read
95 if _read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -070096 _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -070097 if callable(_read_op):
98 return _read_op(version)
Andreas Wundsam27303462013-07-16 12:52:35 -070099 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700100 return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700101
102 def write_op(self, version=None, name=None):
Yotam Harchold7b84202013-07-26 16:08:10 -0700103 ver = ANY if version is None else version.int_version
104 _write_op = None
105 if ver in self.ops:
106 _write_op = self.ops[ver].write or self.ops[ANY].write
107 elif ANY in self.ops:
108 _write_op = self.ops[ANY].write
109 if _write_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -0700110 _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700111 if callable(_write_op):
112 return _write_op(version, name)
Andreas Wundsam27303462013-07-16 12:52:35 -0700113 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700114 return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700115
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700116 @property
117 def is_primitive(self):
118 return self.pub_type in java_primitive_types
119
120 @property
121 def is_array(self):
122 return self.pub_type.endswith("[]")
123
124
Yotam Harchold7b84202013-07-26 16:08:10 -0700125u8 = JType('byte', size=1) \
126 .op(read='bb.readByte()', write='bb.writeByte($name)')
127u8_list = JType('List<U8>', size=1) \
128 .op(read='bb.readByte()', write='bb.writeByte($name)')
129u16 = JType('int', 'int', size=2) \
130 .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))')
131u32 = JType('int', 'int', size=4) \
132 .op(read='bb.readInt()', write='bb.writeInt($name)')
133u32_list = JType('List<U32>', 'int[]', size=4) \
134 .op(read='bb.readInt()', write='bb.writeInt($name)')
135u64 = JType('U64', 'U64', size=8) \
136 .op(read='U64.of(bb.readLong())', write='bb.writeLong($name.getValue())')
137of_port = JType("OFPort") \
138 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") \
139 .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)")
140one_byte_array = JType('byte[]', size=1) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700141 .op(read='ChannelUtilsVer$version.readBytes(bb, 1)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700142two_byte_array = JType('byte[]', size=2) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700143 .op(read='ChannelUtilsVer$version.readBytes(bb, 2)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700144three_byte_array = JType('byte[]', size=3) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700145 .op(read='ChannelUtilsVer$version.readBytes(bb, 3)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700146four_byte_array = JType('byte[]', size=4) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700147 .op(read='ChannelUtilsVer$version.readBytes(bb, 4)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700148five_byte_array = JType('byte[]', size=5) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700149 .op(read='ChannelUtilsVer$version.readBytes(bb, 5)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700150six_byte_array = JType('byte[]', size=6) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700151 .op(read='ChannelUtilsVer$version.readBytes(bb, 6)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700152seven_byte_array = JType('byte[]', size=7) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700153 .op(read='ChannelUtilsVer$version.readBytes(bb, 7)', write='ChannelUtilsVer$version.writeBytes(bb, $name)')
154actions_list = JType('List<OFAction>', size='ChannelUtilsVer$version.calcListSize($name)') \
155 .op(read='ChannelUtilsVer$version.readActionsList(bb, $length)', write='ChannelUtilsVer$version.writeActionsList(bb, $name);')
156instructions_list = JType('List<OFInstruction>', size='ChannelUtilsVer$version.calcListSize($name)') \
157 .op(read='ChannelUtilsVer$version.readInstructionsList(bb, $length)', \
158 write='ChannelUtilsVer$version.writeList(bb, $name)')
159buckets_list = JType('List<OFBucket>', size='ChannelUtilsVer$version.calcListSize($name)') \
160 .op(read='ChannelUtilsVer$version.readBucketList(bb, $length)', \
161 write='ChannelUtilsVer$version.writeList(bb, $name)')
162port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtilsVer$version.calcListSize($name)') \
163 .op(read='ChannelUtilsVer$version.readPhysicalPortList(bb, $length)', \
164 write='ChannelUtilsVer$version.writePhysicalPortList(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700165port_desc = JType('OFPortDesc', size='$name.getLength()') \
166 .op(read='null; // TODO OFPortDescVer$version.READER.read(bb)', \
167 write='$name.writeTo(bb)')
Andreas Wundsam951ada32013-08-01 22:05:38 -0700168packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtilsVer$version.calcListSize($name)') \
169 .op(read='ChannelUtilsVer$version.readPacketQueueList(bb, $length)', \
170 write='ChannelUtilsVer$version.writeList(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700171octets = JType('byte[]', size="$length") \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700172 .op(read='ChannelUtilsVer$version.readBytes(bb, $length)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700173 write='bb.writeBytes($name)')
174of_match = JType('Match', size="$name.getLength()") \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700175 .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
176 write='ChannelUtilsVer$version.writeOFMatch(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700177flow_mod_cmd = JType('OFFlowModCommand', 'short', size="$name.getLength()") \
178 .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
179 .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
180mac_addr = JType('MacAddress', 'byte[]', size=6) \
181 .op(read="MacAddress.read6Bytes(bb)", \
182 write="$name.write6Bytes(bb)")
183port_name = JType('String', size=16) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700184 .op(read='ChannelUtilsVer$version.readFixedLengthString(bb, 16)', \
185 write='ChannelUtilsVer$version.writeFixedLengthString(bb, $name, 16)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700186desc_str = JType('String', size=256) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700187 .op(read='ChannelUtilsVer$version.readFixedLengthString(bb, 256)', \
188 write='ChannelUtilsVer$version.writeFixedLengthString(bb, $name, 256)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700189serial_num = JType('String', size=32) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700190 .op(read='ChannelUtilsVer$version.readFixedLengthString(bb, 32)', \
191 write='ChannelUtilsVer$version.writeFixedLengthString(bb, $name, 32)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700192table_name = JType('String', size=32) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700193 .op(read='ChannelUtilsVer$version.readFixedLengthString(bb, 32)', \
194 write='ChannelUtilsVer$version.writeFixedLengthString(bb, $name, 32)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700195ipv4 = JType("IPv4") \
196 .op(read="IPv4.read4Bytes(bb)", \
197 write="$name.write4Bytes(bb)")
198ipv6 = JType("IPv6") \
199 .op(read="IPv6.read16Bytes(bb)", \
200 write="$name.write16Bytes(bb)")
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700201packetin_reason = JType("OFPacketInReason")\
202 .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)", write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
Andreas Wundsam27303462013-07-16 12:52:35 -0700203
204default_mtype_to_jtype_convert_map = {
205 'uint8_t' : u8,
206 'uint16_t' : u16,
207 'uint32_t' : u32,
208 'uint64_t' : u64,
209 'uint8_t[1]' : one_byte_array,
210 'uint8_t[2]' : two_byte_array,
211 'uint8_t[3]' : three_byte_array,
212 'uint8_t[4]' : four_byte_array,
213 'uint8_t[5]' : five_byte_array,
214 'uint8_t[6]' : six_byte_array,
215 'uint8_t[7]' : seven_byte_array,
216 'of_port_no_t' : of_port,
217 'list(of_action_t)' : actions_list,
218 'list(of_instruction_t)' : instructions_list,
219 'list(of_bucket_t)': buckets_list,
220 'list(of_port_desc_t)' : port_desc_list,
221 'list(of_packet_queue_t)' : packet_queue_list,
222 'list(of_uint32_t)' : u32_list,
223 'list(of_uint8_t)' : u8_list,
224 'of_octets_t' : octets,
225 'of_match_t': of_match,
226 'of_fm_cmd_t': flow_mod_cmd,
227 'of_mac_addr_t': mac_addr,
228 'of_port_desc_t': port_desc,
229 'of_desc_str_t': desc_str,
230 'of_serial_num_t': serial_num,
231 'of_port_name_t': port_name,
232 'of_table_name_t': table_name,
233 'of_ipv4_t': ipv4,
234 'of_ipv6_t': ipv6,
235 'of_wc_bmap_t': JType("Wildcards")
236 }
237
238## This is where we drop in special case handling for certain types
239exceptions = {
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700240 'of_packet_in': {
241 'data' : octets,
242 'reason': packetin_reason
Andreas Wundsam27303462013-07-16 12:52:35 -0700243 },
244}
245
246
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700247enum_wire_types = {
248 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)").cast(min=1<<7),
249 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)").cast(min=1<<15),
250 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)").cast(min=1<<31),
251 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)").cast(min=1<<31)
252}
253
254def convert_enum_wire_type_to_jtype(wire_type):
255 return enum_wire_types[wire_type]
256
Andreas Wundsam27303462013-07-16 12:52:35 -0700257def make_standard_list_jtype(c_type):
258 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
259 if not m:
260 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
261 base_name = m.group(1)
262 java_base_name = name_c_to_caps_camel(base_name)
Yotam Harchold7b84202013-07-26 16:08:10 -0700263 return JType("List<OF%s>" % java_base_name) \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700264 .op(read='ChannelUtilsVer$version.read%sList(bb, $length)' % java_base_name, \
265 write='ChannelUtilsVer$version.write%sList(bb, $name)' % java_base_name)
Andreas Wundsam27303462013-07-16 12:52:35 -0700266
267def convert_to_jtype(obj_name, field_name, c_type):
268 """ Convert from a C type ("uint_32") to a java type ("U32")
269 and return a JType object with the size, internal type, and marshalling functions"""
270 if obj_name in exceptions and field_name in exceptions[obj_name]:
271 return exceptions[obj_name][field_name]
272 elif field_name == "type" and c_type == "uint8_t":
Yotam Harchold7b84202013-07-26 16:08:10 -0700273 return JType("OFType", 'byte', size=1) \
274 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700275 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Yotam Harchold7b84202013-07-26 16:08:10 -0700276 return JType("OFActionType", 'short', size=2) \
277 .op(read='bb.readShort()', write='bb.writeShort($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700278 elif field_name == "version" and c_type == "uint8_t":
Yotam Harchold7b84202013-07-26 16:08:10 -0700279 return JType("OFVersion", 'byte', size=1) \
280 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700281 elif c_type in default_mtype_to_jtype_convert_map:
282 return default_mtype_to_jtype_convert_map[c_type]
283 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
284 return make_standard_list_jtype(c_type)
285 else:
286 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
287 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
288 return JType(jtype)