blob: 38ce1ff7bdf3e10798b0ddbb7ff41d2cfd50f8dd [file] [log] [blame]
Andreas Wundsam46d230f2013-08-02 22:24:06 -07001import loxi_utils.loxi_utils as loxi_utils
Andreas Wundsam27303462013-07-16 12:52:35 -07002import os
3import errno
4import re
5import subprocess
6import time
7
8def name_c_to_camel(name):
9 """ 'of_stats_reply' -> 'ofStatsReply' """
10 name = re.sub(r'^_','', name)
11 tokens = name.split('_')
12 for i in range(1, len(tokens)):
13 tokens[i] = tokens[i].title()
14 return "".join(tokens)
15
16def name_c_to_caps_camel(name):
17 """ 'of_stats_reply' to 'OFStatsReply' """
18 camel = name_c_to_camel(name.title())
19 if camel.startswith('Of'):
20 return camel.replace('Of','OF',1)
21 else:
22 return camel
23
24
Andreas Wundsame916d6f2013-07-30 11:33:58 -070025java_primitive_types = set("byte char short int long".split(" "))
Andreas Wundsam46d230f2013-08-02 22:24:06 -070026java_primitives_info = {
27 'byte' : (True, 8),
28 'char' : (False, 16),
29 'short' : (True, 16),
30 'int' : (True, 32),
31 'long' : (True, 64),
32}
33
34def format_primitive_value(t, value):
35 signed, bits = java_primitives_info[t]
36 max = (1 << bits)-1
37 if value > max:
38 raise Exception("Value %d to large for type %s" % (value, t))
39
40 if signed:
41 max_pos = (1 << (bits-1)) - 1
42
43 if value > max_pos:
44 if t == "long":
45 return str((1 << bits) - value)
46 else:
47 return "(%s) 0x%x" % (t, value)
48 else:
49 return "0x%x" % value
Yotam Harchold7b84202013-07-26 16:08:10 -070050
Andreas Wundsame916d6f2013-07-30 11:33:58 -070051ANY = 0xFFFFFFFFFFFFFFFF
Yotam Harchold7b84202013-07-26 16:08:10 -070052
53class VersionOp:
54 def __init__(self, version=ANY, read=None, write=None):
55 self.version = version
56 self.read = read
57 self.write = write
Andreas Wundsame916d6f2013-07-30 11:33:58 -070058
Yotam Harchold7b84202013-07-26 16:08:10 -070059 def __str__(self):
60 return "[Version: %d, Read: '%s', Write: '%s']" % (self.version, self.read, self.write)
61
Andreas Wundsam27303462013-07-16 12:52:35 -070062class JType(object):
63 """ Wrapper class to hold C to Java type conversion information """
64 def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None):
65 self.pub_type = pub_type # the type we expose externally, e.g. 'U8'
66 if priv_type is None:
67 priv_type = pub_type
68 self.priv_type = priv_type # the internal storage type
69 self.size = size # bytes on the wire; None == variable length or hard to calc
Yotam Harchold7b84202013-07-26 16:08:10 -070070 self.ops = {}
71# if read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -070072# read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -070073# if write_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -070074# write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -070075# self._read_op = read_op
76# self._write_op = write_op
77
Andreas Wundsam46d230f2013-08-02 22:24:06 -070078 def op(self, version=ANY, read=None, write=None, pub_type=ANY):
79 pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ]
80 for pub_type in pub_types:
81 self.ops[(version,pub_type)] = VersionOp(version, read, write)
Yotam Harchold7b84202013-07-26 16:08:10 -070082 return self
Andreas Wundsam27303462013-07-16 12:52:35 -070083
Andreas Wundsam46d230f2013-08-02 22:24:06 -070084 def format_value(self, value, pub_type=True):
85 t = self.pub_type if pub_type else self.priv_type
86 if t in java_primitive_types:
87 return format_primitive_value(t, value)
88 else:
89 return value
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -070090
Andreas Wundsam27303462013-07-16 12:52:35 -070091 @property
92 def public_type(self):
93 """ return the public type """
94 return self.pub_type
95
96 def priv(self):
97 """ return the public type """
98 return self.priv_type
99
100 def has_priv(self):
101 """ Is the private type different from the public one?"""
102 return self.pub_type != self.priv_type
103
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700104 def read_op(self, version=None, length=None, pub_type=True):
Andreas Wundsam27303462013-07-16 12:52:35 -0700105 if length is None:
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700106 length = "length - (bb.readerIndex() - start)";
Andreas Wundsam27303462013-07-16 12:52:35 -0700107
Yotam Harchold7b84202013-07-26 16:08:10 -0700108 ver = ANY if version is None else version.int_version
109 _read_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700110 if (ver, pub_type) in self.ops:
111 _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read
112 elif (ANY, pub_type) in self.ops:
113 _read_op = self.ops[(ANY, pub_type)].read
Yotam Harchold7b84202013-07-26 16:08:10 -0700114 if _read_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -0700115 _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700116 if callable(_read_op):
117 return _read_op(version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700118 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700119 return _read_op.replace("$length", str(length)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700120
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700121 def write_op(self, version=None, name=None, pub_type=True):
Yotam Harchold7b84202013-07-26 16:08:10 -0700122 ver = ANY if version is None else version.int_version
123 _write_op = None
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700124 if (ver, pub_type) in self.ops:
125 _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write
126 elif (ANY, pub_type) in self.ops:
127 _write_op = self.ops[(ANY, pub_type)].write
Yotam Harchold7b84202013-07-26 16:08:10 -0700128 if _write_op is None:
Andreas Wundsam951ada32013-08-01 22:05:38 -0700129 _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type
Yotam Harchold7b84202013-07-26 16:08:10 -0700130 if callable(_write_op):
131 return _write_op(version, name)
Andreas Wundsam27303462013-07-16 12:52:35 -0700132 else:
Yotam Harchold7b84202013-07-26 16:08:10 -0700133 return _write_op.replace("$name", str(name)).replace("$version", version.of_version)
Andreas Wundsam27303462013-07-16 12:52:35 -0700134
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700135 def skip_op(self, version=None, length=None):
136 return self.read_op(version, length)
137
Andreas Wundsame916d6f2013-07-30 11:33:58 -0700138 @property
139 def is_primitive(self):
140 return self.pub_type in java_primitive_types
141
142 @property
143 def is_array(self):
144 return self.pub_type.endswith("[]")
145
146
Yotam Harchold7b84202013-07-26 16:08:10 -0700147u8 = JType('byte', size=1) \
148 .op(read='bb.readByte()', write='bb.writeByte($name)')
149u8_list = JType('List<U8>', size=1) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700150 .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700151u16 = JType('int', 'int', size=2) \
152 .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))')
153u32 = JType('int', 'int', size=4) \
154 .op(read='bb.readInt()', write='bb.writeInt($name)')
155u32_list = JType('List<U32>', 'int[]', size=4) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700156 .op(read='ChannelUtils.readList(bb, $length, U32.READER)', write='ChannelUtils.writeList(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700157u64 = JType('U64', 'U64', size=8) \
158 .op(read='U64.of(bb.readLong())', write='bb.writeLong($name.getValue())')
159of_port = JType("OFPort") \
160 .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") \
161 .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)")
162one_byte_array = JType('byte[]', size=1) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700163 .op(read='ChannelUtils.readBytes(bb, 1)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700164two_byte_array = JType('byte[]', size=2) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700165 .op(read='ChannelUtils.readBytes(bb, 2)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700166three_byte_array = JType('byte[]', size=3) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700167 .op(read='ChannelUtils.readBytes(bb, 3)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700168four_byte_array = JType('byte[]', size=4) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700169 .op(read='ChannelUtils.readBytes(bb, 4)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700170five_byte_array = JType('byte[]', size=5) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700171 .op(read='ChannelUtils.readBytes(bb, 5)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700172six_byte_array = JType('byte[]', size=6) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700173 .op(read='ChannelUtils.readBytes(bb, 6)', write='bb.writeBytes($name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700174seven_byte_array = JType('byte[]', size=7) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700175 .op(read='ChannelUtils.readBytes(bb, 7)', write='bb.writeBytes($name)')
176actions_list = JType('List<OFAction>') \
177 .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
178instructions_list = JType('List<OFInstruction>') \
179 .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \
180 write='ChannelUtils.writeList(bb, $name)')
Andreas Wundsam951ada32013-08-01 22:05:38 -0700181buckets_list = JType('List<OFBucket>', size='ChannelUtilsVer$version.calcListSize($name)') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700182 .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)', write='ChannelUtils.writeList(bb, $name)')
Andreas Wundsam951ada32013-08-01 22:05:38 -0700183port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtilsVer$version.calcListSize($name)') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700184 .op(read='ChannelUtils.readList(bb, $length, OFPhysicalPort.READER)', write='ChannelUtils.writeList(bb, $name)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700185port_desc = JType('OFPortDesc', size='$name.getLength()') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700186 .op(read='OFPortDescVer$version.READER.readFrom(bb)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700187 write='$name.writeTo(bb)')
Andreas Wundsam951ada32013-08-01 22:05:38 -0700188packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtilsVer$version.calcListSize($name)') \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700189 .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)', write='ChannelUtils.writeList(bb, $name);')
Yotam Harchold7b84202013-07-26 16:08:10 -0700190octets = JType('byte[]', size="$length") \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700191 .op(read='ChannelUtils.readBytes(bb, $length)', \
Yotam Harchold7b84202013-07-26 16:08:10 -0700192 write='bb.writeBytes($name)')
193of_match = JType('Match', size="$name.getLength()") \
Andreas Wundsam951ada32013-08-01 22:05:38 -0700194 .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700195 write='$name.writeTo(bb)');
Yotam Harchold7b84202013-07-26 16:08:10 -0700196flow_mod_cmd = JType('OFFlowModCommand', 'short', size="$name.getLength()") \
197 .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \
198 .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)")
199mac_addr = JType('MacAddress', 'byte[]', size=6) \
200 .op(read="MacAddress.read6Bytes(bb)", \
201 write="$name.write6Bytes(bb)")
202port_name = JType('String', size=16) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700203 .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \
204 write='ChannelUtils.writeFixedLengthString(bb, $name, 16)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700205desc_str = JType('String', size=256) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700206 .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \
207 write='ChannelUtils.writeFixedLengthString(bb, $name, 256)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700208serial_num = JType('String', size=32) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700209 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
210 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700211table_name = JType('String', size=32) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700212 .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \
213 write='ChannelUtils.writeFixedLengthString(bb, $name, 32)')
Yotam Harchold7b84202013-07-26 16:08:10 -0700214ipv4 = JType("IPv4") \
215 .op(read="IPv4.read4Bytes(bb)", \
216 write="$name.write4Bytes(bb)")
217ipv6 = JType("IPv6") \
218 .op(read="IPv6.read16Bytes(bb)", \
219 write="$name.write16Bytes(bb)")
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700220packetin_reason = JType("OFPacketInReason")\
221 .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)", write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)")
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700222wildcards = JType("Wildcards")\
223 .op(read="Wildcards.of(bb.readInt())", write="bb.writeInt($name.getInt())");
224transport_port = JType("TransportPort")\
225 .op(read="TransportPort.read2Bytes(bb)", write="$name.write2Bytes(bb)")
226oxm = JType("OFOxm")\
227 .op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
228meter_features = JType("OFMeterFeatures")\
229 .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)")
230
Andreas Wundsam27303462013-07-16 12:52:35 -0700231
232default_mtype_to_jtype_convert_map = {
233 'uint8_t' : u8,
234 'uint16_t' : u16,
235 'uint32_t' : u32,
236 'uint64_t' : u64,
237 'uint8_t[1]' : one_byte_array,
238 'uint8_t[2]' : two_byte_array,
239 'uint8_t[3]' : three_byte_array,
240 'uint8_t[4]' : four_byte_array,
241 'uint8_t[5]' : five_byte_array,
242 'uint8_t[6]' : six_byte_array,
243 'uint8_t[7]' : seven_byte_array,
244 'of_port_no_t' : of_port,
245 'list(of_action_t)' : actions_list,
246 'list(of_instruction_t)' : instructions_list,
247 'list(of_bucket_t)': buckets_list,
248 'list(of_port_desc_t)' : port_desc_list,
249 'list(of_packet_queue_t)' : packet_queue_list,
250 'list(of_uint32_t)' : u32_list,
251 'list(of_uint8_t)' : u8_list,
252 'of_octets_t' : octets,
253 'of_match_t': of_match,
254 'of_fm_cmd_t': flow_mod_cmd,
255 'of_mac_addr_t': mac_addr,
256 'of_port_desc_t': port_desc,
257 'of_desc_str_t': desc_str,
258 'of_serial_num_t': serial_num,
259 'of_port_name_t': port_name,
260 'of_table_name_t': table_name,
261 'of_ipv4_t': ipv4,
262 'of_ipv6_t': ipv6,
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700263 'of_wc_bmap_t': wildcards,
264 'of_oxm_t': oxm,
265 'of_meter_features_t': meter_features,
Andreas Wundsam27303462013-07-16 12:52:35 -0700266 }
267
268## This is where we drop in special case handling for certain types
269exceptions = {
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700270 'of_packet_in': {
271 'data' : octets,
272 'reason': packetin_reason
Andreas Wundsam27303462013-07-16 12:52:35 -0700273 },
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700274 'of_oxm_tcp_src' : {
275 'value' : transport_port
276 },
Andreas Wundsam27303462013-07-16 12:52:35 -0700277}
278
279
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700280enum_wire_types = {
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700281 "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"),
282 "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"),
283 "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"),
284 "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"),
Andreas Wundsambf1dbbd2013-07-30 11:07:59 -0700285}
286
287def convert_enum_wire_type_to_jtype(wire_type):
288 return enum_wire_types[wire_type]
289
Andreas Wundsam27303462013-07-16 12:52:35 -0700290def make_standard_list_jtype(c_type):
291 m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type)
292 if not m:
293 raise Exception("Not a recgonized standard list type declaration: %s" % c_type)
294 base_name = m.group(1)
295 java_base_name = name_c_to_caps_camel(base_name)
Yotam Harchold7b84202013-07-26 16:08:10 -0700296 return JType("List<OF%s>" % java_base_name) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700297 .op(read= 'ChannelUtils.readList(bb, $length, OF%sVer$version.READER)' % java_base_name, \
298 write='ChannelUtils.writeList(bb, $name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700299
300def convert_to_jtype(obj_name, field_name, c_type):
301 """ Convert from a C type ("uint_32") to a java type ("U32")
302 and return a JType object with the size, internal type, and marshalling functions"""
303 if obj_name in exceptions and field_name in exceptions[obj_name]:
304 return exceptions[obj_name][field_name]
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700305 elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t":
Yotam Harchold7b84202013-07-26 16:08:10 -0700306 return JType("OFType", 'byte', size=1) \
307 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700308 elif field_name == "type" and re.match(r'of_action.*', obj_name):
Yotam Harchold7b84202013-07-26 16:08:10 -0700309 return JType("OFActionType", 'short', size=2) \
Andreas Wundsam46d230f2013-08-02 22:24:06 -0700310 .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\
311 .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True)
Andreas Wundsam27303462013-07-16 12:52:35 -0700312 elif field_name == "version" and c_type == "uint8_t":
Yotam Harchold7b84202013-07-26 16:08:10 -0700313 return JType("OFVersion", 'byte', size=1) \
314 .op(read='bb.readByte()', write='bb.writeByte($name)')
Andreas Wundsam27303462013-07-16 12:52:35 -0700315 elif c_type in default_mtype_to_jtype_convert_map:
316 return default_mtype_to_jtype_convert_map[c_type]
317 elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type):
318 return make_standard_list_jtype(c_type)
319 else:
320 print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name)
321 jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type))
322 return JType(jtype)