blob: 76eebd0f0d1efea2a03b4bf2d34e694da28236d4 [file] [log] [blame]
Rich Lanea06d0c32013-03-25 08:52:03 -07001# 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 Lane8a22cda2013-06-19 13:20:07 -070028from collections import namedtuple
29
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -070030import loxi_utils.loxi_utils as loxi_utils
Rich Lane5bcc7c72013-12-01 15:49:49 -080031import py_gen.codegen
32import loxi_globals
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -070033
Rich Lane8a22cda2013-06-19 13:20:07 -070034OFTypeData = namedtuple("OFTypeData", ["init", "pack", "unpack"])
35
Rich Lanec854bae2013-06-19 14:39:51 -070036# 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 Laneda11f8b2013-06-19 15:53:25 -070039type_data_map = {
Rich Lane8a22cda2013-06-19 13:20:07 -070040 '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 Wundsamb566a162013-07-18 19:30:23 -070085 'of_ipv4_t': OFTypeData(
86 init='0',
87 pack='struct.pack("!L", %s)',
88 unpack='%s.read("!L")[0]'),
89
Rich Lane8a22cda2013-06-19 13:20:07 -070090 '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 Lane3b2fd832013-09-24 13:44:08 -0700105 'of_bitmap_128_t': OFTypeData(
106 init='set()',
107 pack='util.pack_bitmap_128(%s)',
108 unpack="util.unpack_bitmap_128(%s)"),
109
Rich Lanebe90eae2013-07-22 16:44:26 -0700110 'of_oxm_t': OFTypeData(
111 init='None',
112 pack='%s.pack()',
Rich Laneedbb4cb2015-01-20 15:42:25 -0800113 unpack='ofp.oxm.oxm.unpack(%s)'),
Rich Lane1adf4212013-12-03 12:59:21 -0800114
115 'of_checksum_128_t': OFTypeData(
116 init='0',
117 pack='util.pack_checksum_128(%s)',
118 unpack="util.unpack_checksum_128(%s)"),
Rich Lane3009c1a2014-11-13 15:43:09 -0800119
120 'of_bitmap_512_t': OFTypeData(
121 init='set()',
122 pack='util.pack_bitmap_512(%s)',
123 unpack="util.unpack_bitmap_512(%s)"),
Rich Lane8a22cda2013-06-19 13:20:07 -0700124}
Rich Lanea06d0c32013-03-25 08:52:03 -0700125
Rich Lanec854bae2013-06-19 14:39:51 -0700126## Fixed length strings
127
128# Map from class name to length
129fixed_length_strings = {
130 'of_port_name_t': 16,
131 'of_table_name_t': 32,
132 'of_serial_num_t': 32,
133 'of_desc_str_t': 256,
Rich Lanef8a3d002014-03-19 13:33:52 -0700134 'of_str64_t': 64,
Rich Lanec854bae2013-06-19 14:39:51 -0700135}
136
137for (cls, length) in fixed_length_strings.items():
Rich Laneda11f8b2013-06-19 15:53:25 -0700138 type_data_map[cls] = OFTypeData(
Rich Lanec854bae2013-06-19 14:39:51 -0700139 init='""',
140 pack='struct.pack("!%ds", %%s)' % length,
141 unpack='%%s.read("!%ds")[0].rstrip("\\x00")' % length)
142
143## Embedded structs
144
145# Map from class name to Python class name
146embedded_structs = {
Rich Laneedbb4cb2015-01-20 15:42:25 -0800147 'of_match_t': 'ofp.match',
148 'of_port_desc_t': 'ofp.port_desc',
149 'of_meter_features_t': 'ofp.meter_features',
150 'of_bsn_vport_t': 'ofp.bsn_vport',
151 'of_table_desc_t': 'ofp.table_desc',
Rich Lanec854bae2013-06-19 14:39:51 -0700152}
153
154for (cls, pyclass) in embedded_structs.items():
Rich Laneda11f8b2013-06-19 15:53:25 -0700155 type_data_map[cls] = OFTypeData(
Rich Lanec854bae2013-06-19 14:39:51 -0700156 init='%s()' % pyclass,
157 pack='%s.pack()',
158 unpack='%s.unpack(%%s)' % pyclass)
159
Rich Laneda11f8b2013-06-19 15:53:25 -0700160## Public interface
Rich Lanec854bae2013-06-19 14:39:51 -0700161
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -0700162def lookup_type_data(oftype, version):
163 return type_data_map.get(loxi_utils.lookup_ir_wiretype(oftype, version))
164
Rich Laneda11f8b2013-06-19 15:53:25 -0700165# Return an initializer expression for the given oftype
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -0700166def gen_init_expr(oftype, version):
167 type_data = lookup_type_data(oftype, version)
Rich Laneda11f8b2013-06-19 15:53:25 -0700168 if type_data and type_data.init:
169 return type_data.init
Rich Lane5bcc7c72013-12-01 15:49:49 -0800170 elif oftype_is_list(oftype):
171 return "[]"
Rich Laneda11f8b2013-06-19 15:53:25 -0700172 else:
173 return "loxi.unimplemented('init %s')" % oftype
Rich Lanea06d0c32013-03-25 08:52:03 -0700174
Rich Laneda11f8b2013-06-19 15:53:25 -0700175# Return a pack expression for the given oftype
176#
177# 'value_expr' is a string of Python code which will evaluate to
178# the value to be packed.
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -0700179def gen_pack_expr(oftype, value_expr, version):
180 type_data = lookup_type_data(oftype, version)
Rich Laneda11f8b2013-06-19 15:53:25 -0700181 if type_data and type_data.pack:
182 return type_data.pack % value_expr
Rich Lane5bcc7c72013-12-01 15:49:49 -0800183 elif oftype_is_list(oftype):
Rich Lanef0bac292013-12-01 15:55:21 -0800184 return "loxi.generic_util.pack_list(%s)" % value_expr
Rich Laneda11f8b2013-06-19 15:53:25 -0700185 else:
186 return "loxi.unimplemented('pack %s')" % oftype
Rich Lanea06d0c32013-03-25 08:52:03 -0700187
Rich Laneda11f8b2013-06-19 15:53:25 -0700188# Return an unpack expression for the given oftype
189#
190# 'reader_expr' is a string of Python code which will evaluate to
191# the OFReader instance used for deserialization.
Andreas Wundsam69ecfdc2013-09-17 13:50:12 -0700192def gen_unpack_expr(oftype, reader_expr, version):
193 type_data = lookup_type_data(oftype, version)
Rich Laneda11f8b2013-06-19 15:53:25 -0700194 if type_data and type_data.unpack:
195 return type_data.unpack % reader_expr
Rich Lane5bcc7c72013-12-01 15:49:49 -0800196 elif oftype_is_list(oftype):
197 ofproto = loxi_globals.ir[version]
198 ofclass = ofproto.class_by_name(oftype_list_elem(oftype))
Rich Lanebabfc332014-10-17 18:05:19 -0700199 assert ofclass, "No class named %r" % oftype_list_elem(oftype)
Rich Lane5bcc7c72013-12-01 15:49:49 -0800200 module_name, class_name = py_gen.codegen.generate_pyname(ofclass)
Rich Laneedbb4cb2015-01-20 15:42:25 -0800201 return 'loxi.generic_util.unpack_list(%s, ofp.%s.%s.unpack)' % \
Rich Lane5bcc7c72013-12-01 15:49:49 -0800202 (reader_expr, module_name, class_name)
Rich Laneda11f8b2013-06-19 15:53:25 -0700203 else:
204 return "loxi.unimplemented('unpack %s')" % oftype
Rich Lane5bcc7c72013-12-01 15:49:49 -0800205
206def oftype_is_list(oftype):
207 return (oftype.find("list(") == 0)
208
209# Converts "list(of_flow_stats_entry_t)" to "of_flow_stats_entry"
210def oftype_list_elem(oftype):
211 assert oftype.find("list(") == 0
212 return oftype[5:-3]