Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 1 | # Copyright 2013, Big Switch Networks, Inc. |
| 2 | # |
| 3 | # LoxiGen is licensed under the Eclipse Public License, version 1.0 (EPL), with |
| 4 | # the following special exception: |
| 5 | # |
| 6 | # LOXI Exception |
| 7 | # |
| 8 | # As a special exception to the terms of the EPL, you may distribute libraries |
| 9 | # generated by LoxiGen (LoxiGen Libraries) under the terms of your choice, provided |
| 10 | # that copyright and licensing notices generated by LoxiGen are not altered or removed |
| 11 | # from the LoxiGen Libraries and the notice provided below is (i) included in |
| 12 | # the LoxiGen Libraries, if distributed in source code form and (ii) included in any |
| 13 | # documentation for the LoxiGen Libraries, if distributed in binary form. |
| 14 | # |
| 15 | # Notice: "Copyright 2013, Big Switch Networks, Inc. This library was generated by the LoxiGen Compiler." |
| 16 | # |
| 17 | # You may not use this file except in compliance with the EPL or LOXI Exception. You may obtain |
| 18 | # a copy of the EPL at: |
| 19 | # |
| 20 | # http://www.eclipse.org/legal/epl-v10.html |
| 21 | # |
| 22 | # Unless required by applicable law or agreed to in writing, software |
| 23 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| 24 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| 25 | # EPL for the specific language governing permissions and limitations |
| 26 | # under the EPL. |
| 27 | |
Rich Lane | 8a22cda | 2013-06-19 13:20:07 -0700 | [diff] [blame] | 28 | from collections import namedtuple |
| 29 | |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 30 | import loxi_utils.loxi_utils as loxi_utils |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 31 | import py_gen.codegen |
| 32 | import loxi_globals |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 33 | |
Rich Lane | 8a22cda | 2013-06-19 13:20:07 -0700 | [diff] [blame] | 34 | OFTypeData = namedtuple("OFTypeData", ["init", "pack", "unpack"]) |
| 35 | |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 36 | # Map from LOXI type name to an object with templates for init, pack, and unpack |
| 37 | # Most types are defined using the convenience code below. This dict should |
| 38 | # only be used directly for special cases such as primitive types. |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 39 | type_data_map = { |
Rich Lane | 8a22cda | 2013-06-19 13:20:07 -0700 | [diff] [blame] | 40 | 'char': OFTypeData( |
| 41 | init='0', |
| 42 | pack='struct.pack("!B", %s)', |
| 43 | unpack='%s.read("!B")[0]'), |
| 44 | |
| 45 | 'uint8_t': OFTypeData( |
| 46 | init='0', |
| 47 | pack='struct.pack("!B", %s)', |
| 48 | unpack='%s.read("!B")[0]'), |
| 49 | |
| 50 | 'uint16_t': OFTypeData( |
| 51 | init='0', |
| 52 | pack='struct.pack("!H", %s)', |
| 53 | unpack='%s.read("!H")[0]'), |
| 54 | |
| 55 | 'uint32_t': OFTypeData( |
| 56 | init='0', |
| 57 | pack='struct.pack("!L", %s)', |
| 58 | unpack='%s.read("!L")[0]'), |
| 59 | |
| 60 | 'uint64_t': OFTypeData( |
| 61 | init='0', |
| 62 | pack='struct.pack("!Q", %s)', |
| 63 | unpack='%s.read("!Q")[0]'), |
| 64 | |
| 65 | 'of_port_no_t': OFTypeData( |
| 66 | init='0', |
| 67 | pack='util.pack_port_no(%s)', |
| 68 | unpack='util.unpack_port_no(%s)'), |
| 69 | |
| 70 | 'of_fm_cmd_t': OFTypeData( |
| 71 | init='0', |
| 72 | pack='util.pack_fm_cmd(%s)', |
| 73 | unpack='util.unpack_fm_cmd(%s)'), |
| 74 | |
| 75 | 'of_wc_bmap_t': OFTypeData( |
| 76 | init='util.init_wc_bmap()', |
| 77 | pack='util.pack_wc_bmap(%s)', |
| 78 | unpack='util.unpack_wc_bmap(%s)'), |
| 79 | |
| 80 | 'of_match_bmap_t': OFTypeData( |
| 81 | init='util.init_match_bmap()', |
| 82 | pack='util.pack_match_bmap(%s)', |
| 83 | unpack='util.unpack_match_bmap(%s)'), |
| 84 | |
Andreas Wundsam | b566a16 | 2013-07-18 19:30:23 -0700 | [diff] [blame] | 85 | 'of_ipv4_t': OFTypeData( |
| 86 | init='0', |
| 87 | pack='struct.pack("!L", %s)', |
| 88 | unpack='%s.read("!L")[0]'), |
| 89 | |
Rich Lane | 8a22cda | 2013-06-19 13:20:07 -0700 | [diff] [blame] | 90 | 'of_ipv6_t': OFTypeData( |
| 91 | init="'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'", |
| 92 | pack='struct.pack("!16s", %s)', |
| 93 | unpack="%s.read('!16s')[0]"), |
| 94 | |
| 95 | 'of_mac_addr_t': OFTypeData( |
| 96 | init='[0,0,0,0,0,0]', |
| 97 | pack='struct.pack("!6B", *%s)', |
| 98 | unpack="list(%s.read('!6B'))"), |
| 99 | |
| 100 | 'of_octets_t': OFTypeData( |
| 101 | init="''", |
| 102 | pack='%s', |
| 103 | unpack='str(%s.read_all())'), |
| 104 | |
Rich Lane | 3b2fd83 | 2013-09-24 13:44:08 -0700 | [diff] [blame] | 105 | 'of_bitmap_128_t': OFTypeData( |
| 106 | init='set()', |
| 107 | pack='util.pack_bitmap_128(%s)', |
| 108 | unpack="util.unpack_bitmap_128(%s)"), |
| 109 | |
Rich Lane | be90eae | 2013-07-22 16:44:26 -0700 | [diff] [blame] | 110 | 'of_oxm_t': OFTypeData( |
| 111 | init='None', |
| 112 | pack='%s.pack()', |
Rich Lane | d50d971 | 2013-11-29 19:40:28 -0800 | [diff] [blame] | 113 | unpack='oxm.oxm.unpack(%s)'), |
Rich Lane | 1adf421 | 2013-12-03 12:59:21 -0800 | [diff] [blame] | 114 | |
| 115 | 'of_checksum_128_t': OFTypeData( |
| 116 | init='0', |
| 117 | pack='util.pack_checksum_128(%s)', |
| 118 | unpack="util.unpack_checksum_128(%s)"), |
Rich Lane | 8a22cda | 2013-06-19 13:20:07 -0700 | [diff] [blame] | 119 | } |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 120 | |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 121 | ## Fixed length strings |
| 122 | |
| 123 | # Map from class name to length |
| 124 | fixed_length_strings = { |
| 125 | 'of_port_name_t': 16, |
| 126 | 'of_table_name_t': 32, |
| 127 | 'of_serial_num_t': 32, |
| 128 | 'of_desc_str_t': 256, |
Rich Lane | f8a3d00 | 2014-03-19 13:33:52 -0700 | [diff] [blame] | 129 | 'of_str64_t': 64, |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 130 | } |
| 131 | |
| 132 | for (cls, length) in fixed_length_strings.items(): |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 133 | type_data_map[cls] = OFTypeData( |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 134 | init='""', |
| 135 | pack='struct.pack("!%ds", %%s)' % length, |
| 136 | unpack='%%s.read("!%ds")[0].rstrip("\\x00")' % length) |
| 137 | |
| 138 | ## Embedded structs |
| 139 | |
| 140 | # Map from class name to Python class name |
| 141 | embedded_structs = { |
| 142 | 'of_match_t': 'common.match', |
| 143 | 'of_port_desc_t': 'common.port_desc', |
| 144 | 'of_meter_features_t': 'common.meter_features', |
Wilson Ng | a5706e6 | 2014-04-09 04:11:20 -0700 | [diff] [blame] | 145 | 'of_bsn_vport_t': 'common.bsn_vport', |
Rich Lane | babfc33 | 2014-10-17 18:05:19 -0700 | [diff] [blame] | 146 | 'of_table_desc_t': 'common.table_desc', |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 147 | } |
| 148 | |
| 149 | for (cls, pyclass) in embedded_structs.items(): |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 150 | type_data_map[cls] = OFTypeData( |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 151 | init='%s()' % pyclass, |
| 152 | pack='%s.pack()', |
| 153 | unpack='%s.unpack(%%s)' % pyclass) |
| 154 | |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 155 | ## Public interface |
Rich Lane | c854bae | 2013-06-19 14:39:51 -0700 | [diff] [blame] | 156 | |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 157 | def lookup_type_data(oftype, version): |
| 158 | return type_data_map.get(loxi_utils.lookup_ir_wiretype(oftype, version)) |
| 159 | |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 160 | # Return an initializer expression for the given oftype |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 161 | def gen_init_expr(oftype, version): |
| 162 | type_data = lookup_type_data(oftype, version) |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 163 | if type_data and type_data.init: |
| 164 | return type_data.init |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 165 | elif oftype_is_list(oftype): |
| 166 | return "[]" |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 167 | else: |
| 168 | return "loxi.unimplemented('init %s')" % oftype |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 169 | |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 170 | # Return a pack expression for the given oftype |
| 171 | # |
| 172 | # 'value_expr' is a string of Python code which will evaluate to |
| 173 | # the value to be packed. |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 174 | def gen_pack_expr(oftype, value_expr, version): |
| 175 | type_data = lookup_type_data(oftype, version) |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 176 | if type_data and type_data.pack: |
| 177 | return type_data.pack % value_expr |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 178 | elif oftype_is_list(oftype): |
Rich Lane | f0bac29 | 2013-12-01 15:55:21 -0800 | [diff] [blame] | 179 | return "loxi.generic_util.pack_list(%s)" % value_expr |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 180 | else: |
| 181 | return "loxi.unimplemented('pack %s')" % oftype |
Rich Lane | a06d0c3 | 2013-03-25 08:52:03 -0700 | [diff] [blame] | 182 | |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 183 | # Return an unpack expression for the given oftype |
| 184 | # |
| 185 | # 'reader_expr' is a string of Python code which will evaluate to |
| 186 | # the OFReader instance used for deserialization. |
Andreas Wundsam | 69ecfdc | 2013-09-17 13:50:12 -0700 | [diff] [blame] | 187 | def gen_unpack_expr(oftype, reader_expr, version): |
| 188 | type_data = lookup_type_data(oftype, version) |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 189 | if type_data and type_data.unpack: |
| 190 | return type_data.unpack % reader_expr |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 191 | elif oftype_is_list(oftype): |
| 192 | ofproto = loxi_globals.ir[version] |
| 193 | ofclass = ofproto.class_by_name(oftype_list_elem(oftype)) |
Rich Lane | babfc33 | 2014-10-17 18:05:19 -0700 | [diff] [blame] | 194 | assert ofclass, "No class named %r" % oftype_list_elem(oftype) |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 195 | module_name, class_name = py_gen.codegen.generate_pyname(ofclass) |
| 196 | return 'loxi.generic_util.unpack_list(%s, %s.%s.unpack)' % \ |
| 197 | (reader_expr, module_name, class_name) |
Rich Lane | da11f8b | 2013-06-19 15:53:25 -0700 | [diff] [blame] | 198 | else: |
| 199 | return "loxi.unimplemented('unpack %s')" % oftype |
Rich Lane | 5bcc7c7 | 2013-12-01 15:49:49 -0800 | [diff] [blame] | 200 | |
| 201 | def oftype_is_list(oftype): |
| 202 | return (oftype.find("list(") == 0) |
| 203 | |
| 204 | # Converts "list(of_flow_stats_entry_t)" to "of_flow_stats_entry" |
| 205 | def oftype_list_elem(oftype): |
| 206 | assert oftype.find("list(") == 0 |
| 207 | return oftype[5:-3] |