Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 1 | import loxi_utils.loxi_utils as loxi_utils |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 2 | import os |
| 3 | import errno |
| 4 | import re |
| 5 | import subprocess |
| 6 | import time |
| 7 | |
| 8 | def 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 | |
| 16 | def 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 | |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 24 | java_primitive_types = set("byte char short int long".split(" ")) |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 25 | |
| 26 | ### info table about java primitive types, for casting literals in the source code |
| 27 | # { name : (signed?, length_in_bits) } |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 28 | java_primitives_info = { |
| 29 | 'byte' : (True, 8), |
| 30 | 'char' : (False, 16), |
| 31 | 'short' : (True, 16), |
| 32 | 'int' : (True, 32), |
| 33 | 'long' : (True, 64), |
| 34 | } |
| 35 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 36 | def format_primitive_literal(t, value): |
| 37 | """ Format a primitive numeric literal for inclusion in the |
| 38 | java source code. Takes care of casting the literal |
| 39 | apropriately for correct representation despite Java's |
| 40 | signed-craziness |
| 41 | """ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 42 | signed, bits = java_primitives_info[t] |
| 43 | max = (1 << bits)-1 |
| 44 | if value > max: |
| 45 | raise Exception("Value %d to large for type %s" % (value, t)) |
| 46 | |
| 47 | if signed: |
| 48 | max_pos = (1 << (bits-1)) - 1 |
| 49 | |
| 50 | if value > max_pos: |
| 51 | if t == "long": |
| 52 | return str((1 << bits) - value) |
| 53 | else: |
| 54 | return "(%s) 0x%x" % (t, value) |
| 55 | else: |
| 56 | return "0x%x" % value |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 57 | |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 58 | ANY = 0xFFFFFFFFFFFFFFFF |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 59 | |
| 60 | class VersionOp: |
| 61 | def __init__(self, version=ANY, read=None, write=None): |
| 62 | self.version = version |
| 63 | self.read = read |
| 64 | self.write = write |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 65 | |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 66 | def __str__(self): |
| 67 | return "[Version: %d, Read: '%s', Write: '%s']" % (self.version, self.read, self.write) |
| 68 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 69 | ### FIXME: This class should really be cleaned up |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 70 | class JType(object): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 71 | """ Wrapper class to hold C to Java type conversion information. JTypes can have a 'public' |
| 72 | and or 'private' java type associated with them and can define how those types can be |
| 73 | read from and written to ChannelBuffers. |
| 74 | |
| 75 | """ |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 76 | def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None): |
| 77 | self.pub_type = pub_type # the type we expose externally, e.g. 'U8' |
| 78 | if priv_type is None: |
| 79 | priv_type = pub_type |
| 80 | self.priv_type = priv_type # the internal storage type |
| 81 | self.size = size # bytes on the wire; None == variable length or hard to calc |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 82 | self.ops = {} |
| 83 | # if read_op is None: |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 84 | # read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 85 | # if write_op is None: |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 86 | # write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 87 | # self._read_op = read_op |
| 88 | # self._write_op = write_op |
| 89 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 90 | def op(self, version=ANY, read=None, write=None, pub_type=ANY): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 91 | """ |
| 92 | define operations to be performed for reading and writing this type |
| 93 | (when read_op, write_op is called). The operations 'read' and 'write' |
| 94 | can either be strings ($name, and $version and $length will be replaced), |
| 95 | or callables (name, version and length) will be passed. |
| 96 | |
| 97 | @param version int OF version to define operation for, or ANY for all |
| 98 | @param pub_type boolean whether to define operations for the public type (True), the |
| 99 | private type(False) or both (ALL) |
| 100 | @param read read expression (either string or callable)s |
| 101 | @param write write expression (either string or callable) |
| 102 | """ |
| 103 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 104 | pub_types = [ pub_type ] if pub_type is not ANY else [ False, True ] |
| 105 | for pub_type in pub_types: |
| 106 | self.ops[(version,pub_type)] = VersionOp(version, read, write) |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 107 | return self |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 108 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 109 | def format_value(self, value, pub_type=True): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 110 | # Format a constant value of this type, for inclusion in the java source code |
| 111 | # For primitive types, takes care of casting the value appropriately, to |
| 112 | # cope with java's signedness limitation |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 113 | t = self.pub_type if pub_type else self.priv_type |
| 114 | if t in java_primitive_types: |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 115 | return format_primitive_literal(t, value) |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 116 | else: |
| 117 | return value |
Andreas Wundsam | bf1dbbd | 2013-07-30 11:07:59 -0700 | [diff] [blame] | 118 | |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 119 | @property |
| 120 | def public_type(self): |
| 121 | """ return the public type """ |
| 122 | return self.pub_type |
| 123 | |
| 124 | def priv(self): |
| 125 | """ return the public type """ |
| 126 | return self.priv_type |
| 127 | |
| 128 | def has_priv(self): |
| 129 | """ Is the private type different from the public one?""" |
| 130 | return self.pub_type != self.priv_type |
| 131 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 132 | def read_op(self, version=None, length=None, pub_type=True): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 133 | """ return a Java stanza that reads a value of this JType from ChannelBuffer bb. |
| 134 | @param version int - OF wire version to generate expression for |
| 135 | @param pub_type boolean use this JTypes 'public' (True), or private (False) representation |
| 136 | @param length string, for operations that need it (e.g., read a list of unknown length) |
| 137 | Java expression evaluating to the byte length to be read. Defaults to the remainig |
| 138 | length of the message. |
| 139 | @return string containing generated Java expression. |
| 140 | """ |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 141 | if length is None: |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 142 | # assumes that |
| 143 | # (1) length of the message has been read to 'length' |
| 144 | # (2) readerIndex at the start of the message has been stored in 'start' |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 145 | length = "length - (bb.readerIndex() - start)"; |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 146 | |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 147 | ver = ANY if version is None else version.int_version |
| 148 | _read_op = None |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 149 | if (ver, pub_type) in self.ops: |
| 150 | _read_op = self.ops[(ver, pub_type)].read or self.ops[(ANY, pub_type)].read |
| 151 | elif (ANY, pub_type) in self.ops: |
| 152 | _read_op = self.ops[(ANY, pub_type)].read |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 153 | if _read_op is None: |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 154 | _read_op = 'ChannelUtilsVer$version.read%s(bb)' % self.pub_type |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 155 | if callable(_read_op): |
| 156 | return _read_op(version) |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 157 | else: |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 158 | return _read_op.replace("$length", str(length)).replace("$version", version.of_version) |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 159 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 160 | def write_op(self, version=None, name=None, pub_type=True): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 161 | """ return a Java stanza that writes a value of this JType contained in Java expression |
| 162 | 'name' to ChannelBuffer bb. |
| 163 | @param name string containing Java expression that evaluations to the value to be written |
| 164 | @param version int - OF wire version to generate expression for |
| 165 | @param pub_type boolean use this JTypes 'public' (True), or private (False) representation |
| 166 | @return string containing generated Java expression. |
| 167 | """ |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 168 | ver = ANY if version is None else version.int_version |
| 169 | _write_op = None |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 170 | if (ver, pub_type) in self.ops: |
| 171 | _write_op = self.ops[(ver, pub_type)].write or self.ops[(ANY, pub_type)].write |
| 172 | elif (ANY, pub_type) in self.ops: |
| 173 | _write_op = self.ops[(ANY, pub_type)].write |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 174 | if _write_op is None: |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 175 | |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 176 | _write_op = 'ChannelUtilsVer$version.write%s(bb, $name)' % self.pub_type |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 177 | if callable(_write_op): |
| 178 | return _write_op(version, name) |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 179 | else: |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 180 | return _write_op.replace("$name", str(name)).replace("$version", version.of_version) |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 181 | |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 182 | def skip_op(self, version=None, length=None): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 183 | """ return a java stanza that skips an instance of JType in the input ChannelBuffer 'bb'. |
| 184 | This is used in the Reader implementations for virtual classes (because after the |
| 185 | discriminator field, the concrete Reader instance will re-read all the fields) |
| 186 | Currently just delegates to read_op + throws away the result.""" |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 187 | return self.read_op(version, length) |
| 188 | |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 189 | @property |
| 190 | def is_primitive(self): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 191 | """ return true if the pub_type is a java primitive type (and thus needs |
| 192 | special treatment, because it doesn't have methods)""" |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 193 | return self.pub_type in java_primitive_types |
| 194 | |
| 195 | @property |
| 196 | def is_array(self): |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 197 | """ return true iff the pub_type is a Java array (and thus requires special |
| 198 | treament for equals / toString etc.) """ |
Andreas Wundsam | e916d6f | 2013-07-30 11:33:58 -0700 | [diff] [blame] | 199 | return self.pub_type.endswith("[]") |
| 200 | |
| 201 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 202 | ##### Predefined JType mappings |
| 203 | # FIXME: This list needs to be pruned / cleaned up. Most of these are schematic. |
| 204 | |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 205 | u8 = JType('byte', size=1) \ |
| 206 | .op(read='bb.readByte()', write='bb.writeByte($name)') |
| 207 | u8_list = JType('List<U8>', size=1) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 208 | .op(read='ChannelUtils.readList(bb, $length, U8.READER)', write='ChannelUtils.writeList(bb, $name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 209 | u16 = JType('int', 'int', size=2) \ |
| 210 | .op(read='U16.f(bb.readShort())', write='bb.writeShort(U16.t($name))') |
| 211 | u32 = JType('int', 'int', size=4) \ |
| 212 | .op(read='bb.readInt()', write='bb.writeInt($name)') |
| 213 | u32_list = JType('List<U32>', 'int[]', size=4) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 214 | .op(read='ChannelUtils.readList(bb, $length, U32.READER)', write='ChannelUtils.writeList(bb, $name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 215 | u64 = JType('U64', 'U64', size=8) \ |
| 216 | .op(read='U64.of(bb.readLong())', write='bb.writeLong($name.getValue())') |
| 217 | of_port = JType("OFPort") \ |
| 218 | .op(version=1, read="OFPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") \ |
| 219 | .op(version=ANY, read="OFPort.read4Bytes(bb)", write="$name.write4Bytes(bb)") |
| 220 | one_byte_array = JType('byte[]', size=1) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 221 | .op(read='ChannelUtils.readBytes(bb, 1)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 222 | two_byte_array = JType('byte[]', size=2) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 223 | .op(read='ChannelUtils.readBytes(bb, 2)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 224 | three_byte_array = JType('byte[]', size=3) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 225 | .op(read='ChannelUtils.readBytes(bb, 3)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 226 | four_byte_array = JType('byte[]', size=4) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 227 | .op(read='ChannelUtils.readBytes(bb, 4)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 228 | five_byte_array = JType('byte[]', size=5) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 229 | .op(read='ChannelUtils.readBytes(bb, 5)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 230 | six_byte_array = JType('byte[]', size=6) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 231 | .op(read='ChannelUtils.readBytes(bb, 6)', write='bb.writeBytes($name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 232 | seven_byte_array = JType('byte[]', size=7) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 233 | .op(read='ChannelUtils.readBytes(bb, 7)', write='bb.writeBytes($name)') |
| 234 | actions_list = JType('List<OFAction>') \ |
| 235 | .op(read='ChannelUtils.readList(bb, $length, OFActionVer$version.READER)', write='ChannelUtils.writeList(bb, $name);') |
| 236 | instructions_list = JType('List<OFInstruction>') \ |
| 237 | .op(read='ChannelUtils.readList(bb, $length, OFInstructionVer$version.READER)', \ |
| 238 | write='ChannelUtils.writeList(bb, $name)') |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 239 | buckets_list = JType('List<OFBucket>', size='ChannelUtilsVer$version.calcListSize($name)') \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 240 | .op(read='ChannelUtils.readList(bb, $length, OFBucketVer$version.READER)', write='ChannelUtils.writeList(bb, $name)') |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 241 | port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtilsVer$version.calcListSize($name)') \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 242 | .op(read='ChannelUtils.readList(bb, $length, OFPhysicalPort.READER)', write='ChannelUtils.writeList(bb, $name)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 243 | port_desc = JType('OFPortDesc', size='$name.getLength()') \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 244 | .op(read='OFPortDescVer$version.READER.readFrom(bb)', \ |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 245 | write='$name.writeTo(bb)') |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 246 | packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtilsVer$version.calcListSize($name)') \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 247 | .op(read='ChannelUtils.readList(bb, $length, OFPacketQueueVer$version.READER)', write='ChannelUtils.writeList(bb, $name);') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 248 | octets = JType('byte[]', size="$length") \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 249 | .op(read='ChannelUtils.readBytes(bb, $length)', \ |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 250 | write='bb.writeBytes($name)') |
| 251 | of_match = JType('Match', size="$name.getLength()") \ |
Andreas Wundsam | 951ada3 | 2013-08-01 22:05:38 -0700 | [diff] [blame] | 252 | .op(read='ChannelUtilsVer$version.readOFMatch(bb)', \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 253 | write='$name.writeTo(bb)'); |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 254 | flow_mod_cmd = JType('OFFlowModCommand', 'short', size="$name.getLength()") \ |
| 255 | .op(version=1, read="bb.readShort()", write="bb.writeShort($name)") \ |
| 256 | .op(version=ANY, read="bb.readByte()", write="bb.writeByte($name)") |
| 257 | mac_addr = JType('MacAddress', 'byte[]', size=6) \ |
| 258 | .op(read="MacAddress.read6Bytes(bb)", \ |
| 259 | write="$name.write6Bytes(bb)") |
| 260 | port_name = JType('String', size=16) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 261 | .op(read='ChannelUtils.readFixedLengthString(bb, 16)', \ |
| 262 | write='ChannelUtils.writeFixedLengthString(bb, $name, 16)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 263 | desc_str = JType('String', size=256) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 264 | .op(read='ChannelUtils.readFixedLengthString(bb, 256)', \ |
| 265 | write='ChannelUtils.writeFixedLengthString(bb, $name, 256)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 266 | serial_num = JType('String', size=32) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 267 | .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \ |
| 268 | write='ChannelUtils.writeFixedLengthString(bb, $name, 32)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 269 | table_name = JType('String', size=32) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 270 | .op(read='ChannelUtils.readFixedLengthString(bb, 32)', \ |
| 271 | write='ChannelUtils.writeFixedLengthString(bb, $name, 32)') |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 272 | ipv4 = JType("IPv4") \ |
| 273 | .op(read="IPv4.read4Bytes(bb)", \ |
| 274 | write="$name.write4Bytes(bb)") |
| 275 | ipv6 = JType("IPv6") \ |
| 276 | .op(read="IPv6.read16Bytes(bb)", \ |
| 277 | write="$name.write16Bytes(bb)") |
Andreas Wundsam | bf1dbbd | 2013-07-30 11:07:59 -0700 | [diff] [blame] | 278 | packetin_reason = JType("OFPacketInReason")\ |
| 279 | .op(read="OFPacketInReasonSerializerVer$version.readFrom(bb)", write="OFPacketInReasonSerializerVer$version.writeTo(bb, $name)") |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 280 | wildcards = JType("Wildcards")\ |
| 281 | .op(read="Wildcards.of(bb.readInt())", write="bb.writeInt($name.getInt())"); |
| 282 | transport_port = JType("TransportPort")\ |
| 283 | .op(read="TransportPort.read2Bytes(bb)", write="$name.write2Bytes(bb)") |
| 284 | oxm = JType("OFOxm")\ |
| 285 | .op(read="OFOxmVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)") |
| 286 | meter_features = JType("OFMeterFeatures")\ |
| 287 | .op(read="OFMeterFeaturesVer$version.READER.readFrom(bb)", write="$name.writeTo(bb)") |
| 288 | |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 289 | |
| 290 | default_mtype_to_jtype_convert_map = { |
| 291 | 'uint8_t' : u8, |
| 292 | 'uint16_t' : u16, |
| 293 | 'uint32_t' : u32, |
| 294 | 'uint64_t' : u64, |
| 295 | 'uint8_t[1]' : one_byte_array, |
| 296 | 'uint8_t[2]' : two_byte_array, |
| 297 | 'uint8_t[3]' : three_byte_array, |
| 298 | 'uint8_t[4]' : four_byte_array, |
| 299 | 'uint8_t[5]' : five_byte_array, |
| 300 | 'uint8_t[6]' : six_byte_array, |
| 301 | 'uint8_t[7]' : seven_byte_array, |
| 302 | 'of_port_no_t' : of_port, |
| 303 | 'list(of_action_t)' : actions_list, |
| 304 | 'list(of_instruction_t)' : instructions_list, |
| 305 | 'list(of_bucket_t)': buckets_list, |
| 306 | 'list(of_port_desc_t)' : port_desc_list, |
| 307 | 'list(of_packet_queue_t)' : packet_queue_list, |
| 308 | 'list(of_uint32_t)' : u32_list, |
| 309 | 'list(of_uint8_t)' : u8_list, |
| 310 | 'of_octets_t' : octets, |
| 311 | 'of_match_t': of_match, |
| 312 | 'of_fm_cmd_t': flow_mod_cmd, |
| 313 | 'of_mac_addr_t': mac_addr, |
| 314 | 'of_port_desc_t': port_desc, |
| 315 | 'of_desc_str_t': desc_str, |
| 316 | 'of_serial_num_t': serial_num, |
| 317 | 'of_port_name_t': port_name, |
| 318 | 'of_table_name_t': table_name, |
| 319 | 'of_ipv4_t': ipv4, |
| 320 | 'of_ipv6_t': ipv6, |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 321 | 'of_wc_bmap_t': wildcards, |
| 322 | 'of_oxm_t': oxm, |
| 323 | 'of_meter_features_t': meter_features, |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 324 | } |
| 325 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 326 | ## Map that defines exceptions from the standard loxi->java mapping scheme |
| 327 | # map of {<loxi_class_name> : { <loxi_member_name> : <JType instance> } } |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 328 | exceptions = { |
Andreas Wundsam | bf1dbbd | 2013-07-30 11:07:59 -0700 | [diff] [blame] | 329 | 'of_packet_in': { |
| 330 | 'data' : octets, |
| 331 | 'reason': packetin_reason |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 332 | }, |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 333 | 'of_oxm_tcp_src' : { |
| 334 | 'value' : transport_port |
| 335 | }, |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 336 | } |
| 337 | |
| 338 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 339 | # Create a default mapping for a list type. Type defauls to List<${java_mapping_of_name}> |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 340 | def make_standard_list_jtype(c_type): |
| 341 | m = re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type) |
| 342 | if not m: |
| 343 | raise Exception("Not a recgonized standard list type declaration: %s" % c_type) |
| 344 | base_name = m.group(1) |
| 345 | java_base_name = name_c_to_caps_camel(base_name) |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 346 | |
| 347 | # read op assumes the class has a public final static field READER that implements |
| 348 | # OFMessageReader<$class> i.e., can deserialize an instance of class from a ChannelBuffer |
| 349 | # write op assumes class implements Writeable |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 350 | return JType("List<OF%s>" % java_base_name) \ |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 351 | .op( |
| 352 | read= 'ChannelUtils.readList(bb, $length, OF%sVer$version.READER)' % java_base_name, \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 353 | write='ChannelUtils.writeList(bb, $name)') |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 354 | |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 355 | |
| 356 | #### main entry point for conversion of LOXI types (c_types) Java types. |
| 357 | # FIXME: This badly needs a refactoring |
| 358 | |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 359 | def convert_to_jtype(obj_name, field_name, c_type): |
| 360 | """ Convert from a C type ("uint_32") to a java type ("U32") |
| 361 | and return a JType object with the size, internal type, and marshalling functions""" |
| 362 | if obj_name in exceptions and field_name in exceptions[obj_name]: |
| 363 | return exceptions[obj_name][field_name] |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 364 | elif ( obj_name == "of_header" or loxi_utils.class_is_message(obj_name)) and field_name == "type" and c_type == "uint8_t": |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 365 | return JType("OFType", 'byte', size=1) \ |
| 366 | .op(read='bb.readByte()', write='bb.writeByte($name)') |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 367 | elif field_name == "type" and re.match(r'of_action.*', obj_name): |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 368 | return JType("OFActionType", 'short', size=2) \ |
Andreas Wundsam | 46d230f | 2013-08-02 22:24:06 -0700 | [diff] [blame] | 369 | .op(read='bb.readShort()', write='bb.writeShort($name)', pub_type=False)\ |
| 370 | .op(read="OFActionTypeSerializerVer$version.readFrom(bb)", write="OFActionTypeSerializerVer$version.writeTo(bb, $name)", pub_type=True) |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 371 | elif field_name == "version" and c_type == "uint8_t": |
Yotam Harchol | d7b8420 | 2013-07-26 16:08:10 -0700 | [diff] [blame] | 372 | return JType("OFVersion", 'byte', size=1) \ |
| 373 | .op(read='bb.readByte()', write='bb.writeByte($name)') |
Andreas Wundsam | 2730346 | 2013-07-16 12:52:35 -0700 | [diff] [blame] | 374 | elif c_type in default_mtype_to_jtype_convert_map: |
| 375 | return default_mtype_to_jtype_convert_map[c_type] |
| 376 | elif re.match(r'list\(of_([a-zA-Z_]+)_t\)', c_type): |
| 377 | return make_standard_list_jtype(c_type) |
| 378 | else: |
| 379 | print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name) |
| 380 | jtype = name_c_to_caps_camel(re.sub(r'_t$', "", c_type)) |
| 381 | return JType(jtype) |
Andreas Wundsam | d8bcedf | 2013-08-03 21:23:37 -0700 | [diff] [blame] | 382 | |
| 383 | |
| 384 | #### Enum specific wiretype definitions |
| 385 | enum_wire_types = { |
| 386 | "uint8_t": JType("byte").op(read="bb.readByte()", write="bb.writeByte($name)"), |
| 387 | "uint16_t": JType("short").op(read="bb.readShort()", write="bb.writeShort($name)"), |
| 388 | "uint32_t": JType("int").op(read="bb.readInt()", write="bb.writeInt($name)"), |
| 389 | "uint64_t": JType("long").op(read="bb.readLong()", write="bb.writeLong($name)"), |
| 390 | } |
| 391 | |
| 392 | def convert_enum_wire_type_to_jtype(wire_type): |
| 393 | return enum_wire_types[wire_type] |