Andreas Wundsam | 40e14f7 | 2013-05-06 14:49:08 -0700 | [diff] [blame] | 1 | import os |
| 2 | import errno |
| 3 | import re |
| 4 | import subprocess |
| 5 | import time |
| 6 | |
| 7 | def name_c_to_camel(name): |
| 8 | """ 'of_stats_reply' -> 'ofStatsReply' """ |
| 9 | tokens = name.split('_') |
| 10 | for i in range(1, len(tokens)): |
| 11 | tokens[i] = tokens[i].title() |
| 12 | return "".join(tokens) |
| 13 | |
| 14 | def name_c_to_caps_camel(name): |
| 15 | """ 'of_stats_reply' to 'OFStatsReply' """ |
| 16 | camel = name_c_to_camel(name.title()) |
| 17 | if camel.startswith('Of'): |
| 18 | return camel.replace('Of','OF',1) |
| 19 | else: |
| 20 | return camel |
| 21 | |
| 22 | |
| 23 | class JType(object): |
| 24 | """ Wrapper class to hold C to Java type conversion information """ |
| 25 | def __init__(self, pub_type, priv_type=None, size=None, read_op=None, write_op=None): |
| 26 | self.pub_type = pub_type # the type we expose externally, e.g. 'U8' |
| 27 | if priv_type is None: |
| 28 | priv_type = pub_type |
| 29 | self.priv_type = priv_type # the internal storage type |
| 30 | self.size = size # bytes on the wire; None == variable length or hard to calc |
| 31 | if read_op is None: |
| 32 | read_op = 'ChannelUtils.read%s(this, "$name", bb)' % self.pub_type |
| 33 | if write_op is None: |
| 34 | write_op = 'ChannelUtils.write($name)' |
| 35 | self._read_op = read_op |
| 36 | self.write_op = write_op |
| 37 | |
| 38 | @property |
| 39 | def public_type(self): |
| 40 | """ return the public type """ |
| 41 | return self.pub_type |
| 42 | |
| 43 | def priv(self): |
| 44 | """ return the public type """ |
| 45 | return self.priv_type |
| 46 | |
| 47 | def has_priv(self): |
| 48 | """ Is the private type different from the public one?""" |
| 49 | return self.pub_type != self.priv_type |
| 50 | |
| 51 | def read_op(self, version=None): |
| 52 | if callable(self._read_op): |
| 53 | return self._read_op(version) |
| 54 | else: |
| 55 | return self._read_op |
| 56 | |
| 57 | hello_elem_list = JType("List<OFHelloElement>", |
| 58 | read_op = 'ChannelUtils.readHelloElementList(bb)', |
| 59 | write_op = 'ChannelUtils.writeHelloElementList(bb)' |
| 60 | ) |
| 61 | |
| 62 | u8 = JType('byte', size=1, read_op='bb.readByte()', |
| 63 | write_op='bb.writeByte($name)') |
| 64 | u16 = JType('int', 'int', size=2, read_op='U16.f(bb.readShort())', |
| 65 | write_op='bb.writeShort(U16.t($name))') |
| 66 | u32 = JType('int', 'int', size=4, read_op='bb.readInt()', |
| 67 | write_op='bb.writeInt($name)') |
| 68 | u64 = JType('U64', 'U64', size=8, read_op='U64.of(bb.readLong())', |
| 69 | write_op='bb.writeLong($name.getLong())') |
| 70 | of_port= JType('OFPort',size=None, |
| 71 | read_op=lambda(version): 'OFPort.ofShort(bb.readShort())' if version.int_version < 2 else 'OFPort.ofInt(bb.readInt())', |
| 72 | write_op='$name.writeTo(bb)') |
| 73 | one_byte_array = JType('byte[]', size=1, |
| 74 | read_op = 'ChannelUtils.readBytes(bb, 1)', |
| 75 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 76 | two_byte_array = JType('byte[]', size=2, |
| 77 | read_op = 'ChannelUtils.readBytes(bb, 2)', |
| 78 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 79 | three_byte_array = JType('byte[]', size=3, |
| 80 | read_op = 'ChannelUtils.readBytes(bb, 3)', |
| 81 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 82 | four_byte_array = JType('byte[]', size=4, |
| 83 | read_op = 'ChannelUtils.readBytes(bb, 4)', |
| 84 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 85 | five_byte_array = JType('byte[]', size=5, |
| 86 | read_op = 'ChannelUtils.readBytes(bb, 5)', |
| 87 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 88 | six_byte_array = JType('byte[]', size=6, |
| 89 | read_op = 'ChannelUtils.readBytes(bb, 6)', |
| 90 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 91 | seven_byte_array = JType('byte[]', size=7, |
| 92 | read_op = 'ChannelUtils.readBytes(bb, 7)', |
| 93 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 94 | actions_list = JType('List<OFAction>', size='ChannelUtils.calcListSize($name)', |
| 95 | read_op = 'ChannelUtils.readActionsList(bb, length - MINIMUM_LENGTH)', |
| 96 | write_op = 'ChannelUtils.writeList(this, $name)') |
| 97 | instructions_list = JType('List<OFInstruction>', size='ChannelUtils.calcListSize($name)', |
| 98 | read_op = 'ChannelUtils.readInstructionsList(bb, length - MINIMUM_LENGTH)', |
| 99 | write_op = 'ChannelUtils.writeList(this, $name)') |
| 100 | buckets_list = JType('List<OFBucket>', size='ChannelUtils.calcListSize($name)', |
| 101 | read_op = 'ChannelUtils.readBucketList(bb, length - MINIMUM_LENGTH)', |
| 102 | write_op = 'ChannelUtils.writeList(this, $name)') |
| 103 | port_desc_list = JType('List<OFPhysicalPort>', size='ChannelUtils.calcListSize($name)', |
| 104 | read_op = 'ChannelUtils.readPhysicalPortList(bb, length - MINIMUM_LENGTH)', |
| 105 | write_op = 'ChannelUtils.writeList(this, $name)') |
| 106 | port_desc = JType('OFPhysicalPort', size='$name.getLength()', |
| 107 | read_op = 'ChannelUtils.readPhysicalPort(bb)', |
| 108 | write_op = 'ChannelUtils.write(this, $name)') |
| 109 | packet_queue_list = JType('List<OFPacketQueue>', size='ChannelUtils.calcListSize($name)', |
| 110 | read_op = 'ChannelUtils.readPacketQueueList(bb, length - MINIMUM_LENGTH)', |
| 111 | write_op = 'ChannelUtils.writeList(this, $name)') |
| 112 | octets = JType('byte[]', size="length - MINIMUM_LENGTH", |
| 113 | read_op = 'ChannelUtils.readBytes(bb, length - MINIMUM_LENGTH)', |
| 114 | write_op = 'ChannelUtils.writeBytes(bb, this.$name)') |
| 115 | of_match = JType('Match', size="$name.getLength()", |
| 116 | read_op = 'ChannelUtils.readOFMatch(bb)', |
| 117 | write_op = 'ChannelUtils.writeOFMatch(this, $name)') |
| 118 | flow_mod_cmd = JType('OFFlowModCmd', size="$name.getLength()", |
| 119 | read_op = 'ChannelUtils.readOFFlowModCmd(bb)', |
| 120 | write_op = 'ChannelUtils.writeOFFlowModCmd(this, $name)') |
| 121 | mac_addr = JType('MacAddress', 'byte[]', size=6, |
| 122 | read_op = 'MacAddress.readFrom(bb)', |
| 123 | write_op = 'ChannelUtils.writeBytes(bb, $name)') |
| 124 | bsn_interface_list = JType("List<OFBsnInterface>", |
| 125 | read_op = 'ChannelUtils.readBsnInterfaceList(bb)', |
| 126 | write_op = 'ChannelUtils.writeBsnInterfaceList(bb)' |
| 127 | ) |
| 128 | meter_band_list = JType("List<OFMeterBand>", |
| 129 | read_op = 'ChannelUtils.readMeterBandList(bb)', |
| 130 | write_op = 'ChannelUtils.writeMeterBandList(bb, $name)' |
| 131 | ) |
| 132 | |
| 133 | |
| 134 | |
| 135 | |
| 136 | |
| 137 | default_mtype_to_jtype_convert_map = { |
| 138 | 'uint8_t' : u8, |
| 139 | 'uint16_t' : u16, |
| 140 | 'uint32_t' : u32, |
| 141 | 'uint64_t' : u64, |
| 142 | 'uint8_t[1]' : one_byte_array, |
| 143 | 'uint8_t[2]' : two_byte_array, |
| 144 | 'uint8_t[3]' : three_byte_array, |
| 145 | 'uint8_t[4]' : four_byte_array, |
| 146 | 'uint8_t[5]' : five_byte_array, |
| 147 | 'uint8_t[6]' : six_byte_array, |
| 148 | 'uint8_t[7]' : seven_byte_array, |
| 149 | 'of_port_no_t' : of_port, |
| 150 | 'of_list_action_t' : actions_list, |
| 151 | 'of_list_instruction_t' : instructions_list, |
| 152 | 'of_list_bucket_t': buckets_list, |
| 153 | 'of_list_port_desc_t' : port_desc_list, |
| 154 | 'of_list_packet_queue_t' : packet_queue_list, |
| 155 | 'of_octets_t' : octets, |
| 156 | 'of_match_t': of_match, |
| 157 | 'of_fm_cmd_t': flow_mod_cmd, |
| 158 | 'of_mac_addr_t': mac_addr, |
| 159 | 'of_port_desc_t': port_desc, |
| 160 | 'of_list_bsn_interface_t': bsn_interface_list, |
| 161 | 'of_list_hello_elem_t': hello_elem_list, |
| 162 | 'of_list_meter_band_t': meter_band_list |
| 163 | } |
| 164 | |
| 165 | ## This is where we drop in special case handling for certain types |
| 166 | exceptions = { |
| 167 | 'OFPacketIn': { |
| 168 | 'data' : octets |
| 169 | }, |
| 170 | } |
| 171 | |
| 172 | |
| 173 | def convert_to_jtype(obj_name, field_name, c_type): |
| 174 | """ Convert from a C type ("uint_32") to a java type ("U32") |
| 175 | and return a JType object with the size, internal type, and marshalling functions""" |
| 176 | if obj_name in exceptions and field_name in exceptions[obj_name]: |
| 177 | return exceptions[obj_name][field_name] |
| 178 | elif c_type in default_mtype_to_jtype_convert_map: |
| 179 | return default_mtype_to_jtype_convert_map[c_type] |
| 180 | else: |
| 181 | print "WARN: Couldn't find java type conversion for '%s' in %s:%s" % (c_type, obj_name, field_name) |
| 182 | jtype = name_c_to_caps_camel(c_type) # not sure... try to fake it |
| 183 | return JType(jtype) |
| 184 | |
| 185 | |
| 186 | def mkdir_p(path): |
| 187 | """ Emulates `mkdir -p` """ |
| 188 | try: |
| 189 | os.makedirs(path) |
| 190 | except OSError as exc: # Python >2.5 |
| 191 | if exc.errno == errno.EEXIST: |
| 192 | pass |
| 193 | else: raise |
| 194 | |
| 195 | def copy_file_with_boiler_plate(src_name, dst_name, with_boiler=True): |
| 196 | with open("java_gen/pre-written/%s" % src_name, "r") as src: |
| 197 | with open(dst_name, "w") as dst: |
| 198 | if with_boiler: |
| 199 | print_boiler_plate(os.path.basename(dst_name), dst) |
| 200 | dst.writelines(src.readlines()) |
| 201 | |
| 202 | def frob(s, **kwargs): |
| 203 | """ Step through string s and for each key in kwargs, |
| 204 | replace $key with kwargs[key] in s. |
| 205 | """ |
| 206 | for k,v in kwargs.iteritems(): |
| 207 | s = s.replace('$%s' % k, v) |
| 208 | return s |
| 209 | |
| 210 | def copy_prewrite_tree(basedir): |
| 211 | """ Recursively copy the directory structure from ./java_gen/pre-write |
| 212 | into $basedir""" |
| 213 | print "Copying pre-written files into %s" % basedir |
| 214 | # subprocess.call("cd java_gen/pre-written && tar cpf - . | ( cd ../../%s && tar xvpf - )" % basedir, |
| 215 | # shell=True) |